Reference the right value of C ++ 11 and std: move

Source: Internet
Author: User

Reference the right value of C ++ 11 and std: move

 

 

 

New Type:

 

What are int and int? All are types. Int is an integer type, and int & is an integer reference type. Int & is also a type. Two quotation marks (&) are a new reference type proposed by C ++ 11. Remember, this is a new type. Meditation 10 times. If you remember this new type, you can solve many questions. Void f (Widget & w) mentioned in objective Modern C ++ makes it easy to understand that w is a value of the new type, it must be a left value rather than a right value. Naturally, you don't have to go over the second page.

There is a new type. Just like defining a new class, there are two things to do next: How to initialize and function match (matching functions based on parameter types ). First read the latter.

 

Void fun (int & a) {cout <
 
  

 

In the main function, fun (a) matches the first fun function. Because the second fun parameter is an int value reference, it cannot match a left value. It is worth noting that although the type of a in the second fun function is the right value reference type, it is a left value because it is a type variable.

So how can we make B match the second fun function? Forced type conversion: Convert B to the reference type of the right value, that is, use static_cast (B ). At this point, it will naturally match the second fun function.

In C ++ 11, static_cast There is a tall alternative std: move. In fact, std: move is similar to the previous one. Forced type conversion makes it match a specific function.

Right Value reference and std: move are proud of how the high efficiency is achieved? 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 const {t. p = nullptr; // otherwise, p} private: char * p ;}; int main () {Test a; will be deleted twice in the destructor; test B (a); return 0 ;}

 

Note that the const parameter of this copy constructor does not exist.

Readers, do you think the Test above is not efficient in copying Constructors? There is almost no efficiency burden. Similarly, you can write an efficient value assignment function.

However, in general, the parameters of the copy constructor have const. If const is set, the parameter t cannot be modified. The code above also shows that assigning t. p to nullptr is required. Because t. p cannot be modified, you have to perform deep replication. Otherwise, the classic shallow replication problem will occur. Needless to say, const's copy constructor is more suitable. After all, we need to copy a copy from a const object.

 

Mobile construction:

 

Performance redemption:

Before C ++ 11, we had to watch that heavyweight classes could only call copy constructors with const and copy a heavyweight Object. If a new type of right value reference is added to C ++ 11, can this right value reference type be used as the constructor parameter? Of course. After all, the constructor parameters of the class have no special requirements. In practice, we will call this constructor a move constructor. The corresponding value assignment operation is called the move assignment function. Their code is also very simple, as follows:

 

Class Test {public: Test (): p (nullptr) {cout <
   
    

 

 

Assist in moving constructor: with the move constructor and the move assignment function, the next step is to help complete the move constructor/move assignment, including the programmer and compiler. If no assistance is provided, you may call the copy constructor instead of the move constructor. In the previous article, we can also see that it helps to complete the moving construction/moving assignment, that is, to make the function that can match the parameter referenced by the right value when calling the function. What cofarm can do is to force an unwanted object to call std: move. The following code is used:

 

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 mobile construction when constructing B, it is obvious that the above Code is not normal at all. Why not directly construct B? No need to move the structure. Some readers may think of this purpose: we can add std: move to a temporary object, such as the return value of operator +. In fact, this is superfluous. Because the compiler treats this temporary object as the right value (accurately speaking, it should be: the dead value), of course it will automatically use the mobile construction.

Is mobile construction a treasure? No. A major advantage of mobile construction is that it can efficiently return a heavyweight class in the function, and the return value of the function will be discussed later. In addition to the function return value, it can also be used inside the function.

 

Std: vector
     
      
G_ids; // global Variable void addIds (std: string id) {g_ids.push_back (std: move (id);} int main () {addIds (1234 ); // when being added to g_ids, a copy constructor is called, and a move constructor std: string my_id = 123456789; addIds (my_id ); // a copy constructor and a move constructor for (auto & e: g_ids) cout <
      
       

 

Some readers may ask why the addIds parameter is not in the const std: string & format, so that the copy constructor is not called for the parameter id when calling the my_id. However, you must call the copy constructor once when the id is pushed to g_ids.

Marked in red, std: move is called to force type conversion for an unwanted object. Why is it unnecessary? Because an object is moved by std: move and serves as a parameter of the move constructor, some resources occupied by this object may be removed, leaving a useless shell. Note: although it is an empty shell, you must ensure that the shell object can be correctly analyzed when moving.

Maybe the readers still think that mobile semantics is a treasure, so the readers may think about it: When the vector container is being resized. With the moving semantics, it is no effort to move objects in a vector from the old address to the new address.

 

 

The return value problem when the right value is referenced:

 

With the right value reference, the reader may write the following code:

 

Test & fun () {Test t ;... return std: move (t);} int main () {Test & tt = fun (); // Which of the following is true? Test tt = fun (); // Which of the following is the correct one for the attacker? Return 0 ;}

 

Undoubtedly, in the main function, you also need to consider whether the tt object is of the Test type or the Test & type. In fact, the big mistake has long been cast in the fun function.

The returned result is only a reference. What about it? The real body has been destroyed in the fun function. As early as Objective C ++, Meyers warned against returning a reference in the function. As mentioned above, the right value reference is also a reference (type )! What are the returned results? Of course it's true! The Code is as follows:

Test fun(){    Test t;    ...    return t;}int main(){Test tt = fun();return 0;}

When a function returns an object, the compiler will regard this object as a right value (accurately, a dead value ). Therefore, you do not need to write return t in the fun function as return std: move (t );

Of course, in fact, the real body of the t variable is still destroyed in the fun function, but all valuable things in the real body are removed. Yes! Just like the Lord of bike, keep your children before they die! In C ++, of course, a child cannot be generated, but a temporary object can be generated through a mobile constructor to remove valuable things. Because it is not moved to the tt variable of the main function, but to the temporary object. So the next temporary object will need to be moved to the tt variable of the main function. This mobile process is undoubtedly a very good classic tutorial. You can run the code to see the entire mobile process. Remember to add the-fno-elide-constructors option when compiling with g ++ to prohibit the compiler from using RVO optimization. This is because the RVO optimization here is more effort-saving than the mobile construction. If this parameter is not disabled, RVO is used first, instead of a mobile constructor.


Initialization:

 

Because the right value reference is also a reference type, it can only be initialized but cannot be assigned a value. In this case, we only need to discuss what type of value can be used to initialize a right value reference. In general, the right value reference can only reference the right value, the literal value, and the dead value. So the question is: what is the right value? One method introduced on the internet is: whether to apply the obtained address symbol to an identifier. If yes, it indicates that it is a left value; otherwise, it indicates a right value. This method seems to work. However, I don't think it is necessary to have a clear score. When writing code, no one will write test code similar to a ++. I personally think it's almost the same to remember the most common ones. For example, for a literal (such as 1 and 'C'), a temporary (anonymous) object (near-dead value), an object converted by std: move (), and the return value of the function. Leave the other right values to the compiler and Scott Meyers. For more information, see What are rvalues, lvalues, xvalues, glvalues, and prvalues?

Another problem is that the reference to the left value (const T &) of const can be referenced by 10 thousand, which can reference both the left value and the right value. This is special and special. If the Test class does not define the move constructor, you can use Test a = std: move (B) to construct variable. The copy constructor of the Test class will be called eventually. If the user does not define the copy constructor of a class, the compiler will automatically synthesize a class if necessary. So the above a variable can certainly be constructed.


Careful Compiler:

 

The previous paragraph seems vaguely mentioned that the compiler will not automatically synthesize a move constructor. Yes. If you define a constructor, copy constructor, destructor, or operator =, the compiler will not automatically synthesize a move constructor and a move assignment function for this class, if necessary. I personally think that when one of the four functions is defined, we can think that this class is not nontrival.

Think about the situations in which we need the Destructor and copy constructor. When some resources (variables) in this class need to be manually managed. Since resources need to be managed, what do you think is the internal implementation of the move constructor generated by the compiler by default? All the Members in the class call std: move to move? Or call the copy constructor to copy a copy? The compiler chooses not to do this kind of tough but unpleasant thing. After all, the const T & mentioned above can reference a right value. No move constructor is available. copy constructor can be built on top of the constructor.

As a class designer, you certainly know whether the resources (variables) are moved or copied. If it is move, use = default to tell the compiler: Don't worry, just move 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; // tell the Compiler Test & operator = (Test &) = default; // tell the compiler private: std: unique_ptr
        
         
P ;}
        


 

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.