Move semantics, move constructors, and rvalue references

Source: Internet
Author: User

C + + references are now categorized as lvalue references (which can take their addresses) and rvalue references (cannot get their addresses). In fact, it is well understood that the lvalue refers to the value of the left value is usually the left side of the equals sign (a variable with a name, a pointer such as * number, etc.), the program can refer to such an lvalue to obtain its address; the right value in an rvalue reference generally refers to the value that appears to the right of the equals sign constants, expressions, functions that are not lvalue-referenced return value ), the program cannot reference the right value to get its address.

One of the purposes of introducing rvalue references is to implement move semantics.

(1) The introduction of mobile semantics is to solve the large data replication, the dynamic application of the memory space to transfer ownership directly, without a large number of data movement, saving space and efficiency .

To implement move semantics, you have to let the compiler know when to copy and when to move semantics, which is where rvalue references work. The move semantics may modify the value of the rvalue, so the Rvalue reference parameter cannot be const.

(2) by constructing a copy constructor to implement the replication semantics, moving the constructor to implement the moving semantics. The copy construct uses the const & reference, while the move constructor uses non-const && references .

(3) The data of the moved semantics surrendered the ownership, in order not to appear the same data area of the destruction two times, to the data of the ownership of the direction of the dynamic application of the memory area pointer to the value bit nullptr, that is, null pointer, the null pointer to execute delete[] is legal.

A (a && h): A (H.A) {    //c++11 New null pointer represents nullptr}

The compiler determines whether an lvalue or an rvalue is in the constructor, and then calls the corresponding copy constructor or move constructor to construct the data.

(4) move assignment operator: His principle is the same as the move constructor, as follows.

operator = (a&& h) {    assert (this = &h);       = nullptr;     = Move (H.A);     = nullptr;     return *this;}

(5) forced movement is to let the left value use the move constructor, forcing it to surrender ownership. the Std::move () function is declared in the utility file ( The left value is cast to an rvalue reference ).

(6) It is important to note that the exception occurs, to try to ensure that the movement of the constructor does not occur , you can pass the Noexcept keyword, here you can ensure that the move constructor thrown out of the exception will be directly called terminate termination program. See "C + + Primer Plus"

Summary: The use of anonymous variables, let them surrender ownership, avoid copying data, can improve the efficiency of the program, so if a temporary variable is no longer necessary, you can force the move semantics, so that the program does not have to do a lot of data replication, especially when the vector as the return value.

"From" http://blog.csdn.net/yusiguyuan/article/details/38616821

1. Rvalue Reference Background introduced

The inefficiency caused by the generation and copying of temporary objects has been a problem that C + + has been criticized. However, the C + + standard allows the compiler to have complete freedom of temporary object generation, thus developing compiler optimization techniques such as Copy Elision, RVO (including Nrvo), which prevent temporary objects from being produced and copied in some cases. The following is a brief introduction to copy Elision, RVO, which is not interested in this can be skipped directly:

(1) Copy Elision

The copy elision technique is designed to prevent some unnecessary temporary objects from being generated and copied, such as:

struct a {    a (int) {}    A (const A &;

Theoretically, the above a = 42; The statement will be divided into three steps: The first step is to construct a temporary object of type A by 42, the second is to construct a with the temporary object for the parameter copy, and the third step to refactor the temporary object. If a is a large class, then the construction and destruction of its temporary objects will result in significant memory overhead. We only need an object A, why not construct a directly with the 42 parameter? Copy elision Technology is doing this optimization.

"description": You can add a print statement in the copy constructor of a to see if there is a call, and if not, congratulations, your compiler supports copy Elision. However, it should be explained that: a copy of the constructor is not called, but its implementation can not have access rights, do not believe you put it in private permissions to try, the compiler will definitely error.

(2) Return value optimization (Rvo,return value optimization)

The return value optimization technique is also designed to prevent some unnecessary temporary objects from being generated and copied, for example:

struct a {    a (int) {}    A (const A &get() {return a ( 1  get();

In theory, the above is a = get (); the statements are executed separately: first create a temporary object in the Get () function (assuming TMP1), then construct the return value with TMP1 as the parameter copy (assuming TMP2), and then construct a with the TMP2 as the parameter copy. It is also accompanied by the destruction of TMP1 and TMP2. If a is a large class, then the construction and destruction of its temporary objects will result in significant memory overhead. The return value optimization technique is used to solve this problem, which avoids the generation and copying of two temporary objects for TMP1 and TMP2.

"description": a) You can add a print statement in the copy constructor of a to see if there is a call, and if not, congratulations, your compiler supports the return value optimization. However, it should be explained that: a copy of the constructor is not called, but its implementation can not have access rights, do not believe you put it in private permissions to try, the compiler will definitely error.

b) In addition to the return value optimization, you may also have heard of an optimization technique called named return value optimization (Named return of Value Optimization,nrvo), which, from the programmer's point of view, is actually the same logic as Rvo. Only its temporary object has a variable name identifier, such as modifying the Get () function above as:

Get () {    A tmp (1//  #1    // do something    return     get//#2 

Think about how many object constructs a type has had since the above modification? Although it looks like there is a display in the structure, #2处看起来也有一次显示地构造, but if your compiler supports Nrvo and copy Elision, you will find the entire A = Get (), the execution of the statement, only one time the construction of a object. If you print the address of the TMP variable before the Get () function return statement, at a = Get (), and then print the address of a after the statement, you will find that the two addresses are the same, which is the result of applying the NRVO technique.

(3) creation and copying of temporary objects that cannot be avoided by copy Elision, Rvo

While techniques such as copy elision and NVO (including Nrvo) prevent the generation and copying of some temporary objects, they do not work in some cases, such as:

Template <typename t>void swap (t& A, t& b) {    T tmp (a);     = B;     = tmp;}

We just want to swap the data owned by A and b two objects, but have to use a temporary object, TMP, to back up one of the objects, and if the T-type object has data that points (or references) from the heap memory, the memory overhead of the deep copy is conceivable. To this end, the C++11 Standard introduces an rvalue reference, which allows the copy of the temporary object to have the move semantics, so that the copy of the temporary object has a shallow copy-like efficiency, which can be used to some extent to resolve the efficiency of the temporary object's deep copy.

2. Left and right values in the C++03 standard

To understand rvalue references, you first have to differentiate between lvalue (Lvalue) and rvalue (rvalue) values.

The c++03 standard divides an expression into lvalue and rvalue, and is "not left or right":

every expression is either a lvalue or an rvalue.

The easiest way to distinguish whether an expression is an lvalue or an rvalue is to see if it can take an address: if so, it is the lvalue; otherwise, it is the right value.

"description": Due to the introduction of rvalue reference, the classification of expressions in the C++11 standard is no longer "non-left-right" so simple, but in order to understand briefly, we only need to distinguish the left-hand value of the right value can be, the C++11 standard in the classification after the description.

3. Binding rules for rvalue references

Rvalue references (rvalue reference,&&) are similar to traditional references (reference,&), and in order to better differentiate between them, references in the traditional sense are referred to as lvalue references (lvalue reference). The following is a simple summary of the binding rules for Lvalue and rvalue references (the function type object is subject to the exception):

(1) A non-const lvalue reference can only be bound to a non-const left value;
(2) A const lvalue reference can be bound to a const lvalue, a non-const lvalue, a const right value, a non-const right value;
(3) A non-const rvalue reference can only be bound to a non-const right value;
(4) A const rvalue reference can be bound to a const right value and a non-const right value.

The test examples are as follows:

structa {a () {}};                             A Lvalue; //non-Const Lvalue objectConstA Const_lvalue;//Const Lvalue ObjectA Rvalue () {returnA ();}//returns a non-const right-valued objectConstA Const_rvalue () {returnA ();}//returns a const right-value object//Rule One: non-const lvalue references can only be bound to non-const lvalue valuesA &lvalue_reference1 = lvalue;//OKA &lvalue_reference2 = Const_lvalue;//ErrorA &lvalue_reference3 = Rvalue ();//ErrorA &lvalue_reference4 = Const_rvalue ();//Error//rule two: const lvalue references can be bound to const lvalue, non-const lvalue, const RVALUE, non-const right valueConstA &const_lvalue_reference1 = lvalue;//OKConstA &const_lvalue_reference2 = Const_lvalue;//OKConstA &const_lvalue_reference3 = Rvalue ();//OKConstA &const_lvalue_reference4 = Const_rvalue ();//OK//Rule Three: non-const rvalue references can only be bound to non-const right-valuesA &&rvalue_reference1 = lvalue;//ErrorA &&rvalue_reference2 = Const_lvalue;//ErrorA &&rvalue_reference3 = Rvalue ();//OKA &&rvalue_reference4 = Const_rvalue ();//Error//Rule four: A const rvalue reference can be bound to a const rvalue and a non-const rvalue and cannot be bound to a left- hand valueConstA &&const_rvalue_reference1 = lvalue;//ErrorConstA &&const_rvalue_reference2 = Const_lvalue;//ErrorConstA &&const_rvalue_reference3 = Rvalue ();//OKConstA &&const_rvalue_reference4 = Const_rvalue ();//OK//Rule Five: Exception to the function typevoidFun () {}typedef decltype-fun; //typedef void Fun ();Fun & lvalue_reference_to_fun = fun;//OKConstFun & const_lvalue_reference_to_fun = fun;//OKFun && rvalue_reference_to_fun = fun;//OKConstFun && const_rvalue_reference_to_fun = fun;//OK

"description": (1) Some support rvalue reference but the lower version of the compiler may allow rvalue reference binding to an lvalue, for example, g++4.4.4 is allowed, but g++4.6.3 is not allowed, clang++3.2 is not allowed, said VS2010 beta version allows, the official version is not allowed, I have no VS2010 environment, has not been tested.

(2) Rvalue references bound to literal constants also conform to the above rules, for example: int &&RR = 123, where the literal value 123, although called a constant, can be of type int instead of const int. For this c++03 standard document 4.4. Section 1 and its footnotes are described below:

If T is a non-class type, the type of the rvalue is the cv-unqualified version of T.
In C + + class Rvalues can have cv-qualified types (because they is objects). This differs from ISO C, in which non-lvalues never has cv-qualified types.

So 123 is a non-const rvalue, int &&rr = 123, and the statement conforms to rule three above.

This, we have learned a lot of rvalue reference point of Knowledge, the following gives a complete use of rvalue reference to implement the move semantics example:

#include <iostream>#include<cstring>#definePRINT (msg) do {std::cout << msg << Std::endl;} while (0)Template<class_tp>structremove_reference {typedef _TP type;}; Template<class_tp>structRemove_reference<_tp&>{typedef _tp type;}; Template<class_tp>structRemove_reference<_tp&&>{typedef _tp type;}; Template<class_tp>Inline TypeName Remove_reference<_Tp>::type&& Move (_tp&&__t) {typedef typename Remove_reference<_Tp>:: Type _up; returnStatic_cast<_up&&>(__t);}classA { Public: A (Const Char*pstr) {PRINT ("Constructor"); M_data= (Pstr! =0? strcpyNew Char[Strlen (PSTR) +1], PSTR):0); } A (ConstA &a) {PRINT ("copy Constructor"); M_data= (A.m_data! =0? strcpyNew Char[Strlen (A.m_data) +1], A.m_data):0); } A&operator=(ConstA &a) {PRINT ("Copy assigment"); if( This! = &a) {delete [] m_data; M_data= (A.m_data! =0? strcpyNew Char[Strlen (A.m_data) +1], A.m_data):0); }        return* This; } A (a&&a): M_data (a.m_data) {PRINT ("Move Constructor"); A.m_data=0; } A&operator= (A &&a) {PRINT ("Move Assigment"); if( This! = &a) {m_data=A.m_data; A.m_data=0; }return* This; }    ~a () {PRINT ("destructor"); delete [] m_data; }Private:    Char*m_data;};voidSwap (a &a, A &b) {A tmp (move (a)); A=Move (b); b=Move (TMP);}intMainintargcChar**ARGV,Char**env) {A A ("123"), B ("456");    Swap (A, b); return 0;}

The output is:

Constructorconstructormove Constructormove Assigmentmove Assigmentdestructordestructordestructor

Move semantics, move constructors, and rvalue references

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.