What is an lvalue, a right value
The most common misconception:
The left-hand side of the equal sign equals the right-hand value.
Both the left and right values are for expressions,
An lvalue is a persistent object that persists after an expression has ended
A right value is a temporary object that no longer exists at the end of an expression
Distinguish:
You can take an address to an expression, or an lvalue, or an rvalue value.
Why are rvalue references introduced?
Std::vector<string> v;
V.push_back ("Hello,world");
- Call string::string (const char *);
- Call string::string (const string&);
- Call String::~string ()
The crux of the problem is that the construction and destruction of temporary objects creates unnecessary copies of resources.
If there is a mechanism to identify temporary objects at the syntactic level, and to "transfer" the resources held by temporary objects to new objects when using temporary objects to construct new objects (copy constructs), this unnecessary copy can be eliminated.
This syntax mechanism is "rvalue reference".
Lvalue Reference
Can be classified as a very good lvalue reference and a constant Lvalue reference , depending on its modifiers
int ia = 10; int &a = IA;
const int IB = 30; int &b = IB;
const int &RI = 20;
A very good lvalue reference can only be bound to a very left value
A constant lvalue reference can be bound to a value of all types, including a non-const lvalue, constant Lvalue, and rvalue (the right value cannot be distinguished by grammatical rules)
Right value vs Temporary object
Vector<int> get_all_scores () {vector<int> vec;vec.push_back (1); Vec.push_back (2); return VEC;} Vector<int> VEC =get_all_scores ();//The three constructors are actually called here
Rvalue reference
rvalue reference int &&refa;
When an rvalue reference is introduced, the binding rules "reference" to "value" are also augmented:
Lvalue references can be bound to an lvalue: int x; int &xr = x;
A non-value lvalue reference cannot be bound to an rvalue: int &r = 0;
Constant Lvalue references can be bound to Lvalue and rvalue:int x; const int &CXR = x; const int &CR = 0;
An rvalue reference can be bound to the right value:int &&r = 0;
An rvalue reference cannot be bound to an lvalue:int x; int &&xr = x;
A constant rvalue reference has no practical significance (after all, rvalue refers to moving semantics, and moving means " modifying ").
Mobile Semantic--std::move
The compiler calls the transfer constructor and the transfer assignment function only on rvalue references , and all named objects can only be lvalue references, and if a named object is known to be no longer being used, you want to call the transfer constructor and the transfer assignment function on it. That is, to use an lvalue reference as an rvalue reference, how do you do it? The standard library provides the function Std::move, which converts an lvalue reference to an rvalue reference in a very simple way.
By moving semantics, we can avoid duplication when it is not necessary.
For an rvalue reference, is it a right value in itself?
Example
1. Definition of strings
#include <stdio.h> #include <string.h> #include <iostream> #include <vector> #include < String>using std::cout;using std::endl;using std::vector;using std::string;class String{public:String (): _pstr ( New Char[1] ()) {}string (const char * pstr): _pstr (New Char[strlen (PSTR) + 1] ()) {cout << "String (const char *)" <&L T endl;strcpy (_pstr, pstr);} Copy constructor string (const string & RHS): _pstr (New Char[strlen (RHS._PSTR) + 1] ()) {cout << "string (const string & RHS) "<< endl;strcpy (_pstr, rhs._pstr);} If the right value is passed, and the copy constructor and the move constructor exist at the same time, the move constructor takes precedence. Move constructor c++11string (String && RHS): _pstr (rhs._pstr) {cout << "string (String && rhs)" << Endl;rhs._pstr = NULL;} Move assignment operator function string & operator= (String && rhs) {cout << "string & operator= (String &&)" <& Lt Endl;if (This! = &rhs) {Delete [] _pstr;_pstr = Rhs._pstr;rhs._pstr = NULL;} return *this;} Assignment operator function string & operator= (const string & RHS) {cout << "String & operator= (const string&)" << endl;if (This! = &rhs) {Delete [] _pstr;_pstr = n EW Char[strlen (RHS._PSTR) + 1] (); strcpy (_pstr, rhs._pstr);} return *this;} ~string () {delete [] _pstr;cout << "~string ()" << Endl;} const char * C_STR () Const{return _pstr;} Friend Std::ostream & operator<< (std::ostream & OS, const String & RHS);p Rivate:char * _PSTR;}; Std::ostream & operator<< (std::ostream & OS, const String & RHS) {OS << rhs._pstr;return os;} int t Est0 (void) {//vector<string> vec;//vec.push_back ("Hello,world"); String S1 ("Hello,world"); cout << "S1 =" << S1 << endl;s1 = String ("Shenzhen"); cout << "S1 =" < ;< S1 << endl;printf ("S1 's address =%p\n", S1.c_str ()); cout << Endl; String S2 ("Wangdao"); cout << "s2 =" << s2 << endl;s2 = Std::move (S1);//explicitly convert an lvalue to an rvalue to use cout << "s 2 = "<< s2 << endl;printf (" S2 's address =%p\n ", S2.C_str ()) cout << "S1 =" << S1 << endl;cout << "..." << Endl;return 0;} void Test1 (void) {int a = 1;int B = 2;&a;&b;//& (a+b);//error, right value//& (a++);//Error, Rvalue & (++A); int * PFLA g = &a;&pFlag;& (*pflag);//&100;//error, literal, rvalue//&string ("Hello"),//error, Rvalue, anonymous object, string S1 (" "Hello"); string S2 ("World");//& (S1 + s2);//error, rvalue const int & m = 1;&m;//Lvalue int && n = 1;//rvalue reference bound to right value &A Mp;n;//int && x = a;//error rvalue reference cannot be bound to an lvalue}void test2 (void) {//const reference can be bound to an lvalue, or to an rvalue,// The const reference cannot distinguish between whether the passed argument is an lvalue or an rvalue////c++11 introduces an rvalue reference, which resolves the problem//string && ref1 = String ("Hello,world"); string S1 ("Hello"); cout << ref1 << endl;const String & ref2 = s1;cout << ref2 << Endl;} int main (void) {test0 ();//test1 ();//test2 (); return 0;}
Summarize:
A very good lvalue reference can only be bound to a very left value and cannot be bound to a constant lvalue, a very right value, and a constant right value.
1) If you allow binding to constant lvalue and constant rvalue, a very good lvalue reference can be used to modify constant lvalue and constant rvalue,
This clearly violates the meaning of its constants.
2) If you allow binding to a very bad right value, it can cause very dangerous situations, because the very right value is a temporary object,
A very good lvalue reference might use a temporary object that has already been destroyed.
C++11 rvalue Reference and move semantics