Move semantics
Completion of the transfer of ownership, when the copy construction and assignment construction, the target object ownership must be handed over to our new object, the original object will lose ownership, the _p pointer will no longer point to the original array;
Left and right values
C Original Definition
- Left Value: can appear to the left or right of the assignment number
- Right value: can only appear to the right of the assignment number
Definition of C + +
- Lvalue: an expression used to identify a Non-temporary object or a Non-member function
- Rvalue: an expression used to identify a temporary object or a value unrelated to any object (a pure right value), or an expression that identifies an object that is about to be invalidated (invalid Value)
Lvalue Reference and Rvalue reference
Lvalue reference:&
Rvalue reference:&&
- Deep copy requires frequent allocation and release of memory, low efficiency
- Purpose of moving semantics: transfer of ownership without re-structuring and destruction
- To be compatible with constructors, the move semantics must be a reference, not a pointer or a normal amount
- A normal reference passes an lvalue to allow the function to modify the target data object internally
- To differentiate Lvalue references, you must pass Rvalue references when implementing move semantics
- To ensure that the target data object can be modified, an rvalue reference must be treated as an lvalue reference within the function
classa{ public: A (): _n (0), _p (nullptr) {}ExplicitAintn): _n (n), _p (New int[n]) {} A (intNint*p): _n (n), _p (p) {} a (a&&that ); A&operator= (A &&that ); Virtual~a () {if(_p) {Delete[]_p, _p =nullptr;} } public: int&operator[](inti); Const int&operator[](intIConst;Private: int_n; int*_p;}; A::a (A&&that ) { //nullptr:c++11 a regular object of a predefined null pointer type nullptr_t//can be implicitly converted to any pointer type and bool type, but cannot be converted to an integer type to replace null_n = that._n, _p = that._p, That._n =0, that._p =nullptr; //*this = that;//This code does not call the following overloaded assignment operator function//A named Rvalue reference that is treated as an lvalue inside a function, not a right value//an Anonymous rvalue reference will be treated as a right-hand value, in theory .....//*this = static_cast<a &&> (that);//equivalent to *this = Std::move (that); //the previous line of code can call the following overloaded move assignment operator, but it may cause the program to crash//because this object that this is pointing to may have just allocated memory, the target data object that the _p field points to is undefined}a& A::operator= (A &&that ) { if(_p)//Deleting this line of code may cause a memory leak Delete[]_p; //you can test for the same object to avoid copying operations, but with little meaning_n = that._n, _p = that._p, That._n =0, that._p =nullptr; return* this;}
Move Semantic overloading
classa{ public: A (): _n (0), _p (nullptr) {}ExplicitAintn): _n (n), _p (New int[n]) {} A (intNint*p): _n (n), _p (p) {}//you can provide both copy semantics and move semantic versions, which use the constant Lvalue reference//the value of the target data object cannot be modified, while the latter can modifyAConstA &that ); A (a&&that ); A & operator = (const A & that);//Deep Copy version A & operator = (a && that);//Move an assignment version Virtual~a () {if(_p) {Delete[]_p, _p =nullptr;} } public: int&operator[](inti); Const int&operator[](intIConst;Private: int_n; int*_p;};intmain () {a A (4); for(inti =0; I <4; i++) {a[i]= i +1; } A B (a);//Call copy Constructorb = a;//Call Normal assignment version//converts an lvalue reference to an rvalue reference, otherwise an lvalue version is called A c (static_cast<a &&> (A));//call to move constructed version C = static_cast<a &&> (A);//Call the Move assignment version return 0;}
Lvalue references can also implement move semantics
classa{ public: A (): _n (0), _p (nullptr) {}ExplicitAintn): _n (n), _p (New int[n]) {} A (intNint*p): _n (n), _p (p) {} a (a& that);//overloading a very heavy version; moving construction semanticsAConstA & that);//overloaded constant version; deep copy construction semanticsA &operator= (A &that);//overloading a very heavy version; moving assignment semanticsA &operator=(ConstA & that);//overloaded constant version; deep copy assignment Semantics Virtual~a () {if(_p) {Delete[]_p, _p =nullptr;} } public: int&operator[](intIThrow(std::out_of_range); Const int&operator[](intIConst Throw(std::out_of_range);Private: int_n; int*_p;}; A::a (A&that ) {_n= that._n, _p = that._p, That._n =0, that._p =nullptr;} A::a (ConstA &that ) { this->_n =that._n; _p=New int[_n]; for(inti =0; I < _n; i++) {_p[i]=that._p[i]; }}a& A::operator= (A &that ) {_n= that._n, _p = that._p, That._n =0, that._p =nullptr; return* this;} A& A::operator=(ConstA &that ) { this->_n =that._n; if(_p) {Delete[]_p; } _p=New int[_n]; for(inti =0; I < _n; i++) {_p[i]=that._p[i]; } return* this;}//main.cppintmain () {A a1;//Default Construction ConstA a2;//Default ConstructionA A3 (a1);//call a::a (A &), Move ConstructionA A4 (a2);//call a::a (const A &), deep Copy construction//for a very mass, you must transform to a constant to make a deep copyA A5 (const_cast<ConstA &> (a1));//call a::a (const A &)A a6, a7, a8;//Default ConstructionA6 = a1;//call a::operator= (A &), move AssignmentA7 = a2;//call a::operator= (const A &), deep copy AssignmentA8 = const_cast<ConstA &> (a1);//call a::operator= (const A &) return 0;}
Meaning of rvalue reference
Rvalue reference can use literal as function actual argument
//do not accept text as the actual parameter, because cannot get the left value of textintFint&x) {return++x;}//accept literal as actual argument, pass Rvalue reference//named Rvalue reference as lvalue, anonymous rvalue reference as right value//inside the function theory so, but actually ...intFint&& X) {return++x;}intmain () {//the error code, the operand of the + + operator must be an lvalue//std::cout << ++10 << std::endl; //There may be a problem passing an rvalue reference, but some compilers might use it as a left-hand valueStd::cout << F (Ten) << std::endl;//One by one ? return 0;}
Meaning of rvalue reference
Avoid writing too many construction and assignment functions
- Whether it is an lvalue reference or an rvalue reference, 2 pairs (4) Construction and assignment functions are required if both copy semantics and move semantics are provided
- If you construct an object by providing a member value individually, a single member needs at least 4 constructors and an assignment function, and a double member needs at least 8 constructs and assignment functions
- Using Rvalue references, You can reduce the amount of code written by a function template
Achieve Perfect forwarding
C + + Learning Note 13: operator overloading (assignment operator 2)