Why use the move semantics
It exists to reduce the cost of copying objects, see the following sections of the code later in this article
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 for an unnamed (anonymous) variableRvalue references are equivalent to "renew" the right value
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 () {DeleteC; } 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;}
Results:
It can be seen from the results that the mobile language 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&lua discussion Group: 69148232
C + + one-std::move lvalue, rvalue, dead value, pure right value, right value reference