C ++ new feature right value reference mobile Constructor

Source: Internet
Author: User

C ++ new feature right value reference mobile Constructor

1. Background introduced by right reference

The loss of efficiency caused by the generation and copying of temporary objects has always been a problem of C ++. However, the C ++ standard allows the compiler to have full degrees of freedom for the generation of temporary objects, thus developing Compiler optimization technologies such as Copy Elision and RVO (including NRVO, they can prevent temporary objects from being generated and copied in some cases. Next, we will briefly introduce Copy Elision and RVO. If you are not interested in this, you can skip it directly:

(1) Copy Elision

The Copy Elision technology is used to prevent unnecessary temporary objects from being generated and copied. For example:

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

Theoretically, the above A = 42; statement will be divided into three steps: the first step is to construct a temporary object of the type from 42, and the second step is to copy and construct a with the temporary object as the parameter, step 3: analyze the temporary object. If A is A large class, the Construction and Analysis of Its temporary object will cause A large memory overhead. We only need one object a. Why not directly construct a with the 42 parameter? Copy Elision technology is doing this optimization.

[Note]: You can add A print statement to the Copy constructor of A to check whether the statement has been called. If not, Congratulations. Your compiler supports Copy Elision. However, it should be noted that although the copy constructor of A has not been called, its implementation cannot have no access permission. If you do not believe it, you can try it in the private permission, and the compiler will certainly report an error.

(2) Return Value Optimization (RVO, Return Value Optimization)

The return value optimization technique is used to prevent unnecessary temporary objects from being generated and copied. For example:

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

Theoretically, the above A = get (); statement will be executed separately: first, create a temporary object (assuming tmp1) in the get () function ), then, we use tmp1 as the parameter to copy and construct the returned value (assuming tmp2). Finally, we use tmp2 as the parameter to copy and construct a, which is accompanied by the analysis structure of tmp1 and tmp2. If A is A large class, the Construction and Analysis of Its temporary object will cause A large memory overhead. The return value optimization technique is used to solve this problem. It can avoid the generation and copying of temporary objects tmp1 and tmp2.

[Note]: a) You can add A print statement to the copy constructor of a to check whether the statement has been called. If not, Congratulations. Your compiler supports Optimization of return values. However, it should be noted that although the copy constructor of A has not been called, its implementation cannot have no access permission. If you do not believe it, you can try it in the private permission, and the compiler will certainly report an error.

B) In addition to Return Value Optimization, you may have heard of an Optimization technique called Named Return Value Optimization (NRVO). From the programmer's perspective, it is actually the same logic as RVO. Only its temporary object has the variable name identifier. For example, modify the get () function as follows:

A get() {    A tmp(1); // #1    // do something    return tmp;}A a = get(); // #2

Think about the number of Object Structures of type A after the above modification? Although #1 looks like a display structure, #2 looks like a display structure, if your compiler supports NRVO and Copy Elision, you will find that the execution process of the entire A = get (); statement is only one construction of the object. If you print the tmp variable address before the get () function return statement, print the address of A after a = get (); statement, you will find that the addresses of a are the same, this is the result of the application of NRVO technology.

(3) Generate and Copy temporary objects that cannot be avoided by Copy Elision and RVO

Although technologies such as Copy Elision and NVO (including NRVO) can avoid the generation and copying of some temporary objects, they may not work in some cases, for example:

template 
 
  void swap(T& a, T& b) {    T tmp(a);    a = b;    b = tmp;}
 

We just want to exchange the data of objects a and B, but we have to use a temporary object tmp to back up one of them. If a T-type object has a point (or reference) for the data allocated from the heap memory, the memory overhead caused by deep copy is conceivable. Therefore, the C ++ 11 standard introduces the right-value reference, which enables the temporary object copy to have the moving semantics, so that the temporary object copy can have the shortest copy efficiency, in this way, the efficiency loss caused by the deep copy of temporary objects can be solved to some extent.

2. The left and right values in the C ++ 03 Standard

To understand the right value reference, you must first distinguish the left value (lvalue) from the right value (rvalue ).

In the C ++ 03 standard, the expression is divided into left and right values, and "non-Left or Right ":

Every expression is either an lvalue or an rvalue.

The easiest way to distinguish between the left and right values of an expression is to see if it can be accessed: If yes, it is the left value; otherwise, it is the right value.

[Note]: due to the introduction of the right value reference, the expression classification in the C ++ 11 standard is no longer as simple as "not left or right", but for a simple understanding, for the moment, we only need to distinguish the right value from the left value. The classification in the C ++ 11 standard will be described later.

3. Binding rules referenced by the right value

The right value reference (&) is similar to the reference (&) in the traditional sense. to better distinguish between them, in the traditional sense, the reference is also called the left value reference ). The following briefly summarizes the binding rules for left-and right-value references (function type objects may have exceptions ):

(1) Non-const left value reference can only be bound to non-const left value;
(2) the reference of the Left const value can be bound to the left const value, left non-const value, right const value, and right non-const value;
(3) A non-const right value reference can only be bound to a non-const right value;
(4) The right reference of const can be bound to the right value of const and the right value of Non-const.

The test example is as follows:

Struct A {A () {}}; A lvalue; // non-const left value object const A const_lvalue; // const left value object A rvalue () {return A () ;}// return A non-const right value object const A const_rvalue () {return ();} // return A const right value object // Rule 1: A non-const left value reference can only be bound to A non-const left value A & lvalue_reference1 = lvalue; // okA & lvalue_reference2 = const_lvalue; // errorA & lvalue_referenpushed = rvalue (); // errorA & lvalue_reference4 = const_rvalue (); // error // Rule 2: const left value reference can be bound to the const left value, non-const left value, const right value, non-const right value const A & const_lvalue_reference1 = lvalue; // okconst A & Signature = const_lvalue; // okconst A & const_lvalue_referene3 = rvalue (); // okconst A & const_lvalue_reference4 = const_rvalue (); // OK // Rule 3: non-const right value reference can only be bound to non-const right value A & rvalue_reference1 = lvalue; // errorA & amp; rvalue_referene3 = rvalue (); // okA & rvalue_reference4 = const_rvalue (); // error // Rule 4: The const right value reference can be bound to the const right value and non-const right value, cannot be bound to the left value const A & const_rvalue_reference1 = lvalue; // errorconst A & amp; st_l (); // okconst A & const_rvalue_reference4 = const_rvalue (); // OK // rule 5: Function Type exception void fun () {} typedef decltype (fun) FUN; // typedef void FUN (); FUN & lvalue_reference_to_fun = fun; // okconst FUN & const_lvalue_reference_to_fun = fun; // okFUN & rvalue_reference_to_fun = fun; // okconst FUN & const_rvalue_reference_to_fun = fun; // OK

[Note]: (1) Some compilers that support right value reference but earlier versions may allow the right value reference to be bound to the left value. For example, g ++ 4.4.4 allows, but g ++ 4.6.3 is not allowed, and clang ++ 3.2 is not allowed. It is said that VS2010 beta is allowed, and the official version is not allowed. I have no VS2010 environment and have not tested it.

(2) the right value reference is bound to a nominal value constant. For example, int & rr = 123;. Although 123 is called a constant, but its type is int rather than const int. Section 4.4.1 of the C ++ 03 standard document and its footer are described as follows:

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 are objects). This differs from iso c, in which non-lvalues never have cv-qualified types.

Therefore, the 123 statement is a non-const right value, and the int & rr = 123; statement conforms to rule 3.

Here, we have learned a lot about reference to the right value. The following shows an example of moving semantics using the right value reference:

#include 
 
  #include 
  
   #define PRINT(msg) do { std::cout << msg << std::endl; } while(0)template 
   
     struct remove_reference        {typedef _Tp type;};template 
    
      struct remove_reference<_Tp&>  {typedef _Tp type;};template 
     
       struct remove_reference<_Tp&&> {typedef _Tp type;};template 
      
       inline typename remove_reference<_Tp>::type&& move(_Tp&& __t) { typedef typename remove_reference<_Tp>::type _Up; return static_cast<_Up&&>(__t);}class A {public: A(const char *pstr) { PRINT("constructor"); m_data = (pstr != 0 ? strcpy(new char[strlen(pstr) + 1], pstr) : 0); } A(const A &a) { PRINT("copy constructor"); m_data = (a.m_data != 0 ? strcpy(new char[strlen(a.m_data) + 1], a.m_data) : 0); } A &operator =(const A &a) { PRINT("copy assigment"); if (this != &a) { delete [] m_data; m_data = (a.m_data != 0 ? strcpy(new 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;};void swap(A &a, A &b) { A tmp(move(a)); a = move(b); b = move(tmp);}int main(int argc, char **argv, char **env) { A a("123"), b("456"); swap(a, b); return 0;}
      
     
    
   
  
 

Output result:

constructorconstructormove constructormove assigmentmove assigmentdestructordestructordestructor


Related Article

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.