C + + 11 rvalue reference and Std::move

Source: Internet
Author: User
Tags shallow copy true true



Reprint Please specify Source: http://blog.csdn.net/luotuo44/article/details/46779063



New type:

What are int and int&? are all types. int is an integer type,int& is an integer reference type. The same int&& is also a type. Two quotation marks && is a new reference type proposed by C + + 11. Remember, this is a new type. Recite it ten times . If you remember this new type, then many questions can be solved. and to the effective modern C + + said void F (widget&& W), it is easy to understand that W is a new type of value, it must be an lvalue rather than the right value, naturally do not have to go to the second page.

A new type appears, just like defining a new class, naturally there are two things to do: How to initialize, function match (according to the parameter type matching function). Look at the latter first.

void Fun (int &a) {    cout<< "int &a" <<A<<ENDL;} void Fun (int &&a) {    cout<< "int &&a" <<A<<ENDL;} int main () {int b = 3;fun (b); return 0;}

The fun (a) in the main function matches the first fun function. Because the second fun parameter is an int rvalue reference, you cannot match an lvalue. It is worth noting that although the type of a of the second fun function is an rvalue reference type, it is an lvalue because it is a type variable.

What can I do to make B match the second fun function? Forces the type cast to cast B to the Rvalue reference type, which is the use of static_cast<int&&> (b). At this point, nature will match the second fun function.

In C + + 11,,static_cast<t&&> has a tall alternative to std::move. In fact, the tall std::move do the same thing as before, forcing the type conversion to match a specific function.

How can rvalue references and Std::move be proud of their efficiency? This article starts with the classic copy constructor, but the example is not classic.

Class Test{public:    Test (): P (nullptr) {}    ~test () {delete [] p;}    Test (Test &t): P (T.P)//Note that the parameter of this copy constructor is not const    {        T.P = nullptr;//Otherwise it will be in a destructor, delete two times P    }private:    char *p;}; int main () {    Test A;    Test B (a);    return 0;}

Note that the parameters of this copy constructor are not Const .

Readers, do you think the above test is not efficient in copy constructor? There is almost no burden of efficiency. Similarly, it is possible to write an efficient assignment function.

However, in general, the parameters of our copy constructors are const. Having a const means that you cannot modify the parameter T, the above code can also be seen: assigning T.P to Nullptr is a must. Because T.P cannot be modified, it has to be deep copied, or there will be a classic shallow copy problem. Needless to say, having a const copy constructor is more appropriate, after all, we need to copy one from a const object.


Mobile Construction:


Performance of Redemption:

Before C + + 11, we could only watch a heavyweight class call a const copy constructor and copy a heavyweight object. A new type rvalue reference is added to C + + 11, can you use this rvalue reference type as a constructor parameter? Of course you can. After all, there are no special requirements for the constructor parameters of a class. It is customary to call such a constructor a move constructor, and the corresponding assignment operation is called a move assignment function. Their code is also very simple, as follows:

Class Test{public:test (): P (nullptr) {cout<< "constructor" <<endl;        } ~test () {delete [] p;    cout<< "destructor" <<endl; } Test (const test& T): P (nullptr), str (T.STR) {if (T.P! = nullptr) {p = new Char[strl            En (T.P) +1];        memcpy (P, T.P, strlen (T.P) +1);    } cout<< "copy constructor" <<endl; } test& operator = (const test& t) {if (this = &t) {Char *tmp = new Char[st            Rlen (T.P) +1];            memcpy (TMP, T.P, strlen (T.P) +1);            delete [] p;            p = tmp;        str = T.STR;        } cout<< "operator =" <<endl;    return *this; } test (Test && T): P (T.P), str (Std::move (T.STR))//How to move is done by the string class {T.P = nullptr;//remember, otherwise the same memory will be duplicated Del    Ete cout<< "Move copy constructor" <<endl; } test& operator = (Test &&t) {if (this!)= &t) {p = T.P;            T.P = nullptr;        str = std::move (T.STR);//How to move done by the string class} cout<< "move operator =" <<endl;    return *this;    }private:char *p; std::string str;};


Assist with move construction: With the move constructor and move assignment function, the next step is to assist in the completion of the move construction/move assignment, including programmers and compilers. If you do not, you might be calling the copy constructor instead of the move constructor. As you can see from the previous article, it is also possible to assist in moving the construction/Movement assignment, which makes it possible to match a function called an rvalue reference in a function call. What the code farmer can do is force aI don't need it.The object called Std::move. As in the following code:

int main () {Test A; Test B = Std::move (a);//Call the move constructor Test C = a;//Call the copy constructor return 0;}

Although the above code calls the move construct when constructing B, it is obvious that the above code is not normal at all, why not construct B directly? No move construction at all. At this point, there may be readers who think of a purpose: we can add std::move to a temporary object, such as the return value of operator +. In fact, it is superfluous. Because the compiler treats the temporary object as an rvalue (which is exactly what it should be: the dead value), it will automatically be able to use the move construct as well.

Is the mobile structure disappointing? No. One of the great advantages of moving constructs is that you can efficiently return a heavyweight class in the function, and the function return value will be said later. It can be used inside a function, except where the function return value is used.

std::vector<std::string> g_ids;//global variable void addids (std::string id) {    g_ids.push_back (Std::move (ID));} int main () {    addids ("1234");//In the process of adding to G_ids, a copy constructor is called once, a move constructor    std::string my_id = "123456789";    Addids (my_id);//The copy constructor is called once, and a move constructor for    (auto &e:g_ids)        cout<<e<<endl;    return 0;}

Some readers may ask why the Addids parameter is not a const std::string &, so you don't have to call the copy constructor for the parameter ID when you call my_id. But don't forget that the copy constructor must be called once when the ID is push into g_ids.

The front is marked in red, and the std::move coercion type conversion is invoked on an unwanted object. Why is that not necessary? Because an object is std::move and as an argument to the move constructor, some of the resources occupied by that object may be removed, leaving an empty shell that is not used. Note that while the shell is empty, when moving, it is also important to ensure that the Shell object can be properly deconstructed.

Perhaps readers still think that the move semantics is disappointing, then readers think about it: when the vector container is expanding. With the move semantics, the objects inside the vector are moved from the old address to the new address without any difficulty.



Return value problem with Rvalue reference:

With an rvalue reference, the reader may write the following code:

test&& Fun () {    Test t;    ...    return Std::move (t);} int main () {    Test && tt = Fun ();//And the next, which is the right one?    Test tt = Fun ();//And who is right?    return 0;}

Undoubtedly, in the main function, you also need to consider whether the TT object is a test type or a test&& type. In fact, the big mistake was already made in the fun function.

Return is just a quote, what about the true flesh? The flesh has been destroyed in the fun function. Meyers in "Effective C + +" warned: Do not return a reference in the function. As already mentioned, rvalue reference is also a reference (type)! Well, what's the return?  Of course it's true! As in the following code:

Test Fun () {    Test T;    ...    return t;} int main () {Test TT = fun (); return 0;}

When the function returns an object, the compiler will treat the object as an rvalue (to be exact, the dead value). So there is no need to write return T as return Std::move (t) in the fun function;

Of course, the true true of the T variable is destroyed in the fun function, but the value in the real thing is removed. Yes, like the great Lord of the Devil, stay with your children before you die! In C + +, of course, you can't spawn a child, but you can create a temporary object by moving the constructor and move something valuable. Because it is not moved to the TT variable of the main function, it is moved to the temporary object only. So then the temporary object is going to move again, moving something valuable into the TT variable of the main function. This mobile process is undoubtedly a good Jinchantuoqiao classic tutorial. The reader can run the code to see the entire movement. Remember, use g++ to join when compiling. -fno-elide-constructors option to prevent the compiler from using Rvo optimizations. Because the Rvo optimization here is more labor-saving than moving the structure. So if you do not disable it, RVO is preferred instead of the move constructor.


Initialization

Because an rvalue reference is also a reference type, it can only be initialized and cannot be assigned a value. In this case, it is only necessary to discuss what type of value can be used to initialize an rvalue reference. In general, rvalue references can only refer to rvalue, literal, and dead values. So the question turns into: What is the right value? One way to introduce online is: to be able to apply the address symbol & to an identifier, if it can be described as an lvalue, otherwise the right value. This method seems to work. However, I do not think it is necessary to be so clear, not in the examination. When writing code, no one would write an exam code like A+++++a. Personally, I think it's almost like remembering the most common ones. For example, the literal (1, ' C '), the temporary (anonymous) object (the impending dead value), the object passed Std::move (), the function returns the value. Other right-hand values, or leave it to the compiler and Scott Meyers. If you really want to scrutiny, you can refer to a question on StackOverflow "What is Rvalues, Lvalues, XValues, glvalues, and prvalues?"

One more question to note is that the Const lvalue reference (const t&) is a universal reference that can reference both Lvalue and rvalue. This is very special, special is very natural. If the test class does not define a move constructor, the user uses test a = Std::move (b) to construct the variable A. The copy constructor of the test class is then eventually called. Copy constructor for a class if the user is not defined, the compiler will automatically synthesize one if necessary. So the A variable above can certainly be constructed.


A cautious compiler:

The previous paragraph seems vaguely said that the compiler does not automatically synthesize a move constructor. Yes. If the user defines a constructor, copy constructor, destructor, operator = any one of them, the compiler does not automatically synthesize a move constituent function and a move assignment function for this class, even if needed. Personally, I think it's because when you define any of those four functions, you can assume that the class is not nontrival.

Consider, under what circumstances, we need destructors and copy constructors. When there are some resources (variables) in this class that need to be managed manually. Now that you have resources to manage, what do you think the internal implementation of the move constructor generated by the compiler default should be? Call Std::move for all members inside the class to move? Or do you call the copy constructor? This laborious but not necessarily pleasing thing, the compiler chooses not to do. After all, there is a const t& that can refer to a right value. Without the move constructor, the copy constructor can be on top.

As the designer of the class, you certainly know whether those resources (variables) are either move or copy. If it's a move, tell the compiler directly with =default: Don't worry, just move it with all the variables. As follows:

Class Test{public:test () p (new int) {}~test () =default; Test (const test&) =delete; test& operator = (const test&) =delete; Test (test &&) =default;//tells the compiler test& operator = (test &&) =default;//tells the compiler private:std::unique_ptr <int> p;}






Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

C + + 11 rvalue references and Std::move

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.