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 quotes && is a new reference type proposed by C + + 11. Remember, this is a new type. Recite it ten times . Suppose you remember this new type, so many questions can be solved. and the void F (widget&& W) mentioned in effective modern C + +. It is very easy to be clear that W is a value for the new type. It must be an lvalue, not an rvalue, and naturally you don't have to go through the second page.

A new type has occurred. 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. Cannot match an lvalue value. 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.

So how do you make B match a 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 did almost the same thing as he said before. Forcing type conversions makes it possible 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 sample is not classic.

Class Test{public:    Test (): P (nullptr) {}    ~test () {delete [] p;}    Test (Test &t): P (T.P)//Note that the reference to 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 constructors? Almost no matter what the efficiency of the burden AH.

Similarly, it is possible to write an efficient assignment function.

However, in general our copy constructors have a const number of references. Having a const means that you cannot change the number of the parameters T. The above code can also be seen: assigning T.P to Nullptr is a must.

Since T.P cannot be changed, it has to be deep copied. Otherwise, a classic shallow copy problem will occur. Alone. A copy constructor with Const is more suitable, after all, we need to copy one from a const object.



Mobile Construction:


Performance of Redemption:

Before C + + 11, we were only able to see the heavyweight class simply invoking a const copy constructor and copying a heavyweight object. Add a new type rvalue reference to C + + 11, can you use this rvalue reference type as the parameter of the constructor function? Of course I can. After all, there is no particular requirement for the class's constructor parameters.

In practice, we call this constructor a move constructor, and the corresponding assignment operation is called a move assignment function.

Their code is also very easy. For example, the following:

Class Test{public:test (): P (nullptr) {cout<< "constructor" <<endl;        } ~test () {cout<< "destructor" <<endl;    delete [] p;        } Test (const test& T): P (nullptr), str (T.STR) {cout<< "copy constructor" <<endl;            if (T.P! = nullptr) {p = new Char[strlen (T.P) +1];        memcpy (P, T.P, strlen (T.P) +1);        }} test& operator = (const test& t) {cout<< "operator =" <<endl;            if (this = &t) {char *tmp =nullptr;                if (T.P! = nullptr) {tmp = new Char[strlen (T.P) +1];            memcpy (TMP, T.P, strlen (T.P) +1);            } delete [] p;            p = tmp;        str = T.STR;    } return *this; } test (Test && T) noexcept:p (T.P), str (Std::move (T.STR))//How to move by the string class {cout<< "Move copy Co        Nstructor "<<endl; T.P = nulLptr;//remembers. Otherwise the same memory will be repeated delete} test& operator = (Test &&t) noexcept {cout<< "move operator =" <&lt        ; Endl;            if (this = &t) {p = T.P;            T.P = nullptr;    str = std::move (T.STR);//How to move the String class is complete} return *this;    }private:char *p; std::string str;};


Assistance completed move construct: With move constructor and move assignment function. The next step is to help complete the move construction/move assignment. Contains the program ape and compiler. Assuming no assistance is possible, the copy constructor may be called instead of the move constructor. It is also possible to see, in the past, the move construct/move assignment, which in fact makes it possible to match a function called an rvalue reference in a function call. What the code farmer can do is force ano need.The object called Std::move.

such as 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. But obviously the above code is not normal at all, why not construct B directly? There is no need to move the structure. At this point, one might 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.

Since the compiler will treat this temporary object as an rvalue (which is exactly what it should be: the Dead value), of course, you can use the mobile construct on your own initiative.

Is the mobile structure disappointing? No.

One of the great advantages of moving constructs is the ability to efficiently return a heavyweight class in a function. 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");//The copy constructor is called once during a join to G_ids. One 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 Addids's participation is not a const std::string &, so it is not necessary to call the copy constructor for the parameter ID when calling my_id.

But don't forget, when the ID is push into the g_ids, you will need to call the copy constructor once.

The front is marked in red, and a std::move coercion type conversion is invoked on an unwanted object.

Why does it not need to be? Some of the resources that the object occupies may be removed because an object is std::move and as a function of the move constructor. Leave an empty shell that is not practical. attention. Although it is empty shell. However, when moving, it is also ensured that the Shell object can be properly deconstructed.

Perhaps the reader still thinks that the moving 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.

The only thing returned is a reference. The flesh has been destroyed in the fun function. Meyers in "Effective C + +" warned: Do not return a reference in the function. The previous article has also been said. An 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 you don't need to be in the fun function. Write return T as return Std::move (t);

Of course. In fact, the true true of the T variable is destroyed in the fun function, but something valuable inside 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 cannot spawn a child, but you can generate a temporary object by moving the constructor function. To remove something of value. Because it is not moved to the TT variable of the main function. Just moved to a temporary object. So the next time the object is going to move again, moving something valuable into the TT variable of the main function. This mobile process is undoubtedly a very good Jinchantuoqiao classic tutorial. The reader can execute the code and be able to see the entire movement process.

remember. When compiling with g++ , Add the -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, assuming that it doesn't work, it takes precedence over the Rvo, not the move constructor.


Initialization

Because an rvalue reference is also a reference type. So it's only possible to initialize and not assign values. Now that's it. That just needs to discuss what type of value talent is 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 do this online is to be able to apply the fetch address symbol & to an identifier. Assume that it is an lvalue, otherwise it is a right-hand value. This method seems to work.

Just, I don't think it's necessary to be so clear, it's not a test. When writing code, no one would write an exam code like A+++++a. Personally, I think. Remember that the most common ones are almost the same.

For example, the literal amount (1. such as ' C '), temporary (anonymous) object (impending dead value). The function returns a value after the Std::move () object is converted.

The other right value. or leave it to the compiler and Scott Meyers. Assuming really want to scrutiny, can participate in StackOverflow on a question "What is rvalues, Lvalues, XValues, glvalues, and prvalues?"

Another question needs to be explained. The const lvalue Reference (const t&) is a universal reference. Can reference both Lvalue values. You can also refer to the right value. This is very special, special very natural. Suppose the test class does not define a move constructor. However, the user uses test a = Std::move (b) to construct the variable A. Then finally the copy constructor of the test class is called. The copy constructor of a class assumes that the user is not defined. The compiler will actively synthesize one on its own, if necessary. So the A variable above can certainly be constructed.


Careful compiler:

The previous paragraph seems vaguely stated that the compiler does not actively synthesize a move constructor itself. Yes. Assume that the user defines the copy constructor. destructors, operator = no matter what, the compiler does not voluntarily synthesize a move constituent function and a move assignment function for this class. Even if it needs to be used. Detailed rules can point here. Personally, I think it's because. When you define any of those four functions, you can feel that the class is not nontrival.

Consider, under what circumstances, we need to destructor and copy constructor.

There are some resources (variables) in this class that need to be managed manually. Since there are resources to manage. So what do you think the internal implementation of the move constructor generated by the compiler by default should be? Call Std::move for all members of the class to move? Or do you call the copy constructor? Such a strenuous but not pleasing thing, the compiler chose not to do. After all, there is a const t& that can refer to a right value. There is no move constructor. The copy constructor is available on top.

As the designer of the class, you certainly know whether those resources (variables) are move or copy. Let's say move. Then tell the compiler directly with =default: Don't worry. Move directly with all variables. For example, the following:

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;}






C + + 11 rvalue reference 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.