C + + 11 move semantics, Std::move lvalue, Rvalue, dead value, pure right value, rvalue reference

Source: Internet
Author: User

Why use the move semantics

First look at the following code

//rvalue_reference.cpp: Defines the entry point of the console application. //#include"stdafx.h"#include<iostream>classhugemem{ Public: Hugemem (intSize): SZ (size) {Pintdata=New int[SZ]; } hugemem (ConstHugemem &h): Sz (H.SZ) {Pintdata=New int[SZ];  for(inti =0; I < sz; i++) Pintdata[i]=H.pintdata[i]; }    ~Hugemem () {DeletePintdata []; }    int*Pintdata; intsz;}; Hugemem gettemp () {returnHugemem (1024x768);}int_tmain (intARGC, _tchar*argv[]) {Hugemem a=gettemp (); return 0;}

The above code copy constructor is called two times, one time from the Gettemp function with a temporary value generated by HUGEMEM () as the return value, and the other time by a temporary value to construct the variable a in main. Destructors were called three times. This process is expensive when the pointer points to very large memory when the copy is constructed. It is worrying that the production and destruction of temporary variables and the occurrence of copy construction is essentially transparent to programmers and does not affect the correctness of the program, so even if the problem results in poor performance, it is not easy for programmers to detect.

The key problem is that when a temporary object is constructed and disposed, it does not seem to make much sense, so can we not allocate memory when the temporary object constructs a, i.e. not using the so-called copy constructor?

At this point, the moving semantics arises.

To understand the move semantics, you need to start with Lvalue and Rvalue.

Left and right values

There are two ways to judge left and right values

1. The value to the left of the equals sign is called the Lvalue and the right side of the equals sign is called the Rvalue

2. In addition, in C + + There is also a way to identify the address, known as the left value, can not take the address, no name is the right value

For example:

A = B + C

A value is left value on the left side of the equals sign

B+c on the right side of the equals sign is called the right value

A famous, can take the address called the left value

B+c No name, can not take address called Right value

A pure right value, a dead value

In C + + 11, the right value is divided into a pure right value and a dead value

Where the pure right value is the standard right value in c++98 is used to mark a temporary variable or a value that is not a root object.

The dead value is an expression in C + + 11 that is associated with an rvalue reference, which is usually the object being moved (for his use), such as the return value of the function returning the Rvalue reference t&&, the return value of Std::move, or the conversion to t&& The return value of the type conversion function, while the remaining can identify the function, and the value of the object belongs to the Lvalue.

In C + + 11, all values must be left, pure right, and three of the dead values in any of the one by one types.

Rvalue reference

In C + + 11, an rvalue reference is a type that references a right value, in fact, the right value is usually not a huge name, we can only find his presence by reference. In general, we can only get his reference from an rvalue expression.

int && c = RetValue ();

Reference to C + + 98 (lvalue Reference)

References in C + + 98 are generally referred to as lvalue references

int d = 100;
int & dd = d;//This is an lvalue reference inside the c++98

An lvalue reference is an alias for a named variable value, and an rvalue reference is an alias Rvalue reference to an unnamed (anonymous) variable that is equivalent to the right value "renew"

In the example above Rvalue reference, RetValue () After the function returns an rvalue expression, his life is terminated, and the declaration of the rvalue reference gives him "rebirth", and his life cycle will be the same as his rvalue reference to the life cycle of C, as long as C is alive. The right-hand temporary variable will survive forever.

So compared to the following statement

CObj C = RetValue ()

CObj && C = RetValue ()

You construct and refactor one more time without using rvalue references

The type of an rvalue reference is declared as if RetValue () returns an rvalue, and normally an rvalue reference is not bound to an lvalue. For example, the following code is not compiled

int d = 100;
int & dd = d;//This is an lvalue reference inside the c++98
int && DD2 = d;//cannot be compiled, compiler hints cannot bind rvalue reference to left value

Correspondingly, is it possible to bind an lvalue reference to an rvalue, for example:

int & d = 100;//not possible, compile error

The above code shows that the corresponding lvalue reference cannot be bound to a right value

But C98 has a constant lvalue reference that is const T&, which in C98 is a "Magnum" reference type, which he can accept, a very constant lvalue, a const lvalue, and an rvalue to initialize it for example:

int d = 100;

const int e = 100;

const int & c = d;//accepts a very good left-hand value
const int & v = e;//accepts a constant left value
const int & z = 3 + 4;//accept a right value

Constant Lvalue references in c98 are often used to reduce the overhead of temporary objects, such as:

int Add (const T & s1,const T & S2);

In C + + 11, you can also use rvalue references to make function arguments, which can also reduce the overhead of temporary variables such as:

void Test (Ctestobj && a)//the value of reference A can also be modified inside the function

For the purposes of this example, we can write this function

void Test (Ctestobj && a)
{
Ctestobj B = Std::move (a);
}

Std::move, forcing an lvalue to be an rvalue, using move semantics presupposes that ctestobj also needs to add an rvalue reference as a parameter to the move constructor.

This way the temporary object of the Ctestobj class (that is, the temporary value returned by returnvalue) contains a large number of pointers that can be "stolen" from the temporary object. In fact, the existence of rvalue references is always related to the move semantics.

What happens if we don't declare a move constructor for Ctestobj, but only declare a constructor with a constant lvalue as a parameter? As we said before, a constant lvalue reference is a universal reference, regardless of the constant lvalue, the very left value, and the right value. So if we don't declare the move constructor, the following statement:

Ctestobj B = Std::move (a)

A copy constructor that calls a constant lvalue reference as a parameter. This is a very safe design----move is not at least a copy can be executed. Therefore, the Program page declares a copy constructor of a constant lvalue reference to a parameter for the class that declares the move constructor, so that the construct can be copied if the move is not made.

There is also a constant rvalue reference for semantic integrity in C + + 11, for example:

Const T && a = Returnrvalue ()

A constant rvalue reference, however, is generally useless.

Std::move forced conversion to right value

Std::move does not move anything, his only function is to convert the Lvalue to an rvalue, and then we can refer to this value with an rvalue reference for moving semantics.

//rvalue_reference.cpp: Defines the entry point of the console application. //#include"stdafx.h"#include<iostream>classmoveable{ Public: Moveable (): I (New int(3)) {}    ~moveable () {Deletei;} Moveable (ConstMoveable & S): I (New int(*s.i)) {} moveable (moveable&&s): I (S.I) {s.i=nullptr; }    int*i;};int_tmain (intARGC, _tchar*argv[])    {Moveable A; Moveable C= A;//The copy constructor is called heremoveable D; Moveable E (Std::move (d));//The move constructor is called hereStd::cout<< *d.i << Std::endl;//There will be a violation of access at this time I pointer to nullptr         return 0;}

The above is a typical example of misuse of std::move, and in fact it must be the programmer's clear need to convert. For example, in the code above the programmer should know that a conversion to the right value of a can no longer be used. Whether we need to convert to an rvalue reference or should be an object that the real life cycle is about to end.

Here is an example of using std::move correctly

//rvalue_reference.cpp: Defines the entry point of the console application. //#include"stdafx.h"#include<iostream>classhugemem{ Public: Hugemem (intSize): SZ (Size >0? Size:1) {C=New int[SZ]; }    ~Hugemem () {Delete[] C; } hugemem (Hugemem&&HM): SZ (HM.SZ), C (hm.c) {hm.c=nullptr; }    int*C; intsz;};classmoveable{ Public: Moveable (): I (New int(3)), H (1024x768) {}    ~moveable () {Deletei;} Moveable (Moveable&&s): I (S.I), H (Std::move (s.h)) {s.i=nullptr;    } Hugemem H; int*i;}; Moveable gettemp () {Moveable temp=moveable (); Std::cout<< Std::hex <<"Huge mem gettemp:"<<" @"<< temp.h.c <<Std::endl; returntemp;}int_tmain (intARGC, _tchar*argv[])    {Moveable A (gettemp ()); Std::cout<< Std::hex <<"Huge mem main:"<<" @"<< a.h.c <<Std::endl; return 0;}

Operation Result:

It can be seen from the result that the moving semantics solves the copy cost of copy language, and the performance is obviously when the copy memory is large.

What would happen if there were no std::move?

Because the parameters of the move constructor are (T && b), the value that the Rvalue reference parameter can receive is a very right value, and no other value can be converted to an rvalue reference parameter, so you must use the Std::move

C + + 11 move semantics, Std::move lvalue, Rvalue, dead value, pure right value, rvalue reference

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.