This article to introduce the content and the title of the same, about C + + 11 of these features on-line introduction of a lot of articles, after looking at some of the more critical points to summarize the record, the article is relatively long. A lot of code examples are given, all compiled and run-tested, in the hope of helping to understand these more important features in C + + 11.
About the definition of lvalue and rvalue
The left and right values exist in C, but the sense of presence is not high, in C + + especially c++11 the two concepts are more important, the left is the name of the variable (object), can be assigned, can be used in multiple statements, and the right value, is temporary variable (object), no name, can only appear in a statement, cannot be assigned a value.
Before c++11, the right value cannot be referenced, and the maximum is to bind a right value with a constant reference, such as:
const int& i = 3;
In this case, the right value cannot be modified. But actually the right value can be modified, such as:
T().set().get();
T is a class, set is a function that assigns a value to a variable in T, and get is used to remove the value of the variable. In this sentence, T () generates a temporary object, which is the right value, and set () modifies the value of the variable and modifies the right value.
Since the right value can be modified, an rvalue reference can be implemented. Rvalue references make it easy to solve problems in real-world projects and achieve attractive solutions.
Rvalue reference
The declaration symbol for the lvalue is "&", and for the left value, the declaration symbol for the right value is "&&".
Give an example program as follows
#include <iostream>void process_value(int& i) { std::cout << "LValue processed: " << i << std::endl; } void process_value(int&& i) { std::cout << "RValue processed: " << i << std::endl; } int main() { int a = 0; process_value(a); process_value(1); }
The results are as follows
[email protected]:~$ g++ -std=c++11 test.cpp[email protected]:~$ ./a.out LValue processed: 0RValue processed: 1
The Process_value function is overloaded, accepting both lvalue and rvalue values, respectively. As you can see from the output, the temporary objects are treated as rvalue values.
Here's a question:
The type of x is an rvalue reference, pointing to an rvalue, but does X itself have an lvalue or an rvalue? C++11 makes a distinction between:
Things that are declared as rvalue reference can be lvalues or rvalues. The distinguishing criterion is: if it has a name, then it is an lvalue. Otherwise, it is an rvalue.
A slight modification to the above procedure would confirm this.
#include <iostream>void process_value(int& i) { std::cout << "LValue processed: " << i << std::endl; } void process_value(int&& i) { std::cout << "RValue processed: " << std::endl; } int main() { int a = 0; process_value(a); int&& x = 3; process_value(x); }
[email protected]:~$ g++ -std=c++11 test.cpp[email protected]:~$ ./a.out LValue processed: 0LValue processed: 3
X is an rvalue reference that points to an rvalue of 3, but since X is a name, X is considered an lvalue here, so when the function is overloaded, it is selected as the first function.
Meaning of rvalue reference
Intuitive meaning: To renew a temporary variable, that is, to renew the right value, because the right value dies after the expression ends, and if you want to continue to use the right value, expensive copy constructors are used. (For this part, recommend a book "in-depth understanding of c++11")
Rvalue references are used to support the transfer semantics. Transfer semantics can move resources (heaps, system objects, and so on) from one object to another, reducing the creation, copying, and destruction of unnecessary temporary objects, which can significantly improve the performance of C + + applications. Maintenance (creation and destruction) of temporary objects has a serious impact on performance.
The transfer semantics are relative to the copy semantics and can be analogous to the cut and copy of a file, and when we copy a file from one directory to another, the speed is much slower than the cut.
By transferring semantics, the resources in the temporary object can be transferred to other objects.
In the existing C + + mechanism, we can define copy constructors and assignment functions. To implement transfer semantics, you need to define a transfer constructor, and you can also define a transfer assignment operator. The transfer constructor and transfer assignment operators are called for copy and assignment of the right value. If the transfer constructor and the transfer copy operator are not defined, then the existing mechanism is followed, and the copy constructor and assignment operator are called.
Normal functions and operators can also use rvalue reference operators to implement the transfer semantics.
Transfer semantics and Transfer constructors and transfer copy operators
The copy constructor and copy assignment operators are implemented as examples of a simple string class.
class MyString {private:char* _data; size_t _len; void _init_data (const char *s) {_data = new char[_len+1]; memcpy (_data, S, _len); _data[_len] = ' + '; } public:mystring () {_data = NULL; _len = 0; } MyString (const char* p) {_len = strlen (p); _init_data (P); } MyString (const mystring& str) {_len = Str._len; _init_data (Str._data); Std::cout << "Copy Constructor is called! Source: "<< str._data << Std::endl; } mystring& operator= (const mystring& str) {if (This! = &str) {_len = Str._len; _init_data (Str._data); } std::cout << "Copy assignment is called! Source: "<< str._data << Std::endl; return *this; } virtual ~mystring () {if (_data) free (_data); } }; int main () {MyString A; A = MyString ("Hello"); Std::vector<mystring> VEC; Vec.push_back (MyString ("World")); }
Copy Assignment is called! source: Hello Copy Constructor is called! source: World
This string class has basically met the needs of our presentation. In the main function, the operation of the call copy constructor and the copy assignment operator are implemented. MyString ("Hello") and MyString ("World") are temporary objects, which are right values. Although they are temporary, the program still invokes copy construction and copy assignment, resulting in meaningless resource requests and actions released. If you can directly use the resources that the temporary object has already requested, you can save resources and save time on resource requests and releases. This is precisely the purpose of defining the transfer semantics.
Let's define the transfer constructor first.
MyString(MyString&& str) { std::cout << "Move Constructor is called! source: " << str._data << std::endl; _len = str._len; _data = str._data; str._len = 0; str._data = NULL; }
The following points need to be noted against the code:
- The symbol for the parameter (right value) must be an rvalue reference symbol, or "&&".
- The parameter (rvalue) cannot be a constant because we need to modify the right value.
- Resource links and tags for parameters (rvalue) must be modified. Otherwise, the destructor for the right value frees the resource. The resources transferred to the new object are also invalid.
Now we define the transfer assignment operator.
MyString& operator=(MyString&& str) { std::cout << "Move Assignment is called! source: " << str._data << std::endl; if (this != &str) { _len = str._len; _data = str._data; str._len = 0; str._data = NULL; } return *this; }
The problem to note here is the same as the transfer constructor.
With the addition of the transfer constructor and the transfer copy operator, our program runs with the following results:
As a result, the compiler distinguishes the left and right values, calls the transfer constructor and the transfer assignment operator on the right value. It saves resources and improves the efficiency of program operation.
With Rvalue reference and transfer semantics, when we design and implement classes, we design transfer constructors and transfer assignment functions to improve the efficiency of the application for classes that require a large amount of resources to be dynamically requested.
About Std::move () and Std::forward re-recommend a book: "Effective modern C + +"
English version, here is an article about the translation of ITEM25 good
Please look here.
But this is a good summary.
std::move执行一个无条件的转化到右值。它本身并不移动任何东西;std::forward把其参数转换为右值,仅仅在那个参数被绑定到一个右值时;std::move和std::forward在运行时(runtime)都不做任何事。
C + + 11 Lvalue, rvalue, lvalue Reference, rvalue reference, Std::move, Std::foward