On the right value reference, transfer semantics and perfect forwarding _c language in c++11

Source: Internet
Author: User
Tags anonymous constant

1. Left value and right value:

C + + for the left and right values do not have a standard definition, but there is a widely accepted saying: You can take the address, the name, not temporary is the value of the left, can not take the address, there is no name, temporary is the right value.

The immediate number is visible, the value returned by the function is the right value, not the anonymous object (including the variable), the reference returned by the function, the const object, and so on are all left values.

Essentially understanding, creating and destroying the controls behind the compiler, programmers can only make sure that the bank code is valid, that is, the right value (including the immediate number), and the user created, through the scope rules to know its lifetime, is the left value (including the local variables returned by the function reference and const objects), such as:

int& foo () {int tmp; return tmp;}

int fooo () {int tmp; return tmp;}

int a=10;

const int B;

int& Temp=foo ();/Although legal, temp references an object

int tempp=fooo () that no longer exists;

In the above code, A,TEMP and foo() both are very much left, B is the constant left, fooo() is the very right value, 10 is the constant right value, one thing to pay special attention to: the return of the reference is the left value (can take the address)!

In general, the compiler is not allowed to make changes to the right value (because the lifetime of the right value is not controlled by the programmer, this is especially true for built-in type objects, even if the right value is changed, but C + + allows the use of a right value object to invoke a member function, although this is allowed, but for the same reason it is best not to do so.

2. Right Value reference:

The representation method for the right value reference is

 datatype&& variable

The right value reference is a new feature of C + + 11, so the reference to C + + 98 is a left-valued reference. The right value reference is used to bind to the right value, the lifetime of the right value that is bound to be destroyed after the right value is extended to the lifetime with the right value reference bound to it, the existence of the right value reference is not to replace the left value reference, but to make full use of the right value (especially temporary objects) to reduce object construction and destructors for efficiency purposes, for example, for the following functions:

(Demo is a class)
Demo foo () { 
  demo tmp;
  return tmp;
}

The following operations are performed without the compiler Rvo (return value optimization) Optimization:

Demo X=foo ();

Three constructors (TMP, X, temporary objects) will be called, and three destructors will be called when the object is destroyed, and if the right value is referenced:

demo&& X=foo ();

Then there is no need for the construction of X, and temporary objects that would have been destroyed will extend the lifetime to x as the binding of X (it is understood that x gives the temporary object a legal status: a name), you need to increase the efficiency (the cost is that TMP needs to occupy 4 bytes of space, but this is trivial) .

The right value reference and the left value refer to the binding rule:

A constant left-value reference can be bound to a constant and a very left value, a constant, and a very right value;

A very strong left-value reference can only be bound to the very left value;

The very right value reference can only be bound to the very right value (vs2013 can also be bound to a constant right value);

A constant right value reference can only be bound to a constant and a very right value (a very literal right value reference exists only for semantic integrity, and a constant left-value reference can do so).

Although you can see from the binding rules that a constant left-value reference can also be bound to a right value, however, it is clear that the value of the right value can not be changed, the right value reference can be used to implement the transfer semantics, because the right value reference is usually to change the bound right value, so the bound right value cannot be const .

Note: The right value reference is the left value!

3. Transfer semantics (move semantics):

One of the purposes of the right value reference being introduced is to implement the transfer semantics, transfer semantics can transfer ownership of resources (heaps, system objects, etc.) from one object (usually an anonymous temporary object) to another, thereby reducing object construction and destruction operations and increasing program efficiency (which is explained in the 2 example). The transfer semantics are relative to the copy semantics. From the transfer semantics, it can be seen that, in fact, transfer semantics is not a new concept, and it is actually used in c++98/03 languages and libraries, such as the omission of copy constructors in some cases (copy constructor elision in Some contexts), smart pointer copy (auto_ptr "copy"), linked list stitching (list::splice) and container permutations (swap on containers), etc., but there is no unified syntax and semantic support

Although normal functions and operators can also use the right value reference to implement the transfer semantics (examples in 2), the transfer semantics are usually implemented through the transfer constructor and the transfer assignment operator. The prototype for the transfer constructor is Classname(Typename&&) , and the copy constructor's prototype is Classname(const Typename&) , The transfer constructor is not automatically generated by the compiler, it needs to be defined itself, only the transfer constructor is defined, and the compiler generates the copy constructor, and if the passed parameter is a left value, the copy constructor is called, and the transfer constructor is called instead.

For example:

Class demo{public

:

  Demo ():p (New int[10000]{};

  Demo (demo&& lre): Arr (Lre.arr), size (lra.size) {lre.arr=null;} Transfer constructor

  Demo (const demo& LRE): arr (new int[10000)), size (arr.size) {for

    (int cou=0;cou<10000;++cou)

      Arr[cou]=lew.arr[cou];

  }

Private:

  int size;

  int* arr;

}

As you can see from the above code, the copy constructor has reopened a 10000-type array in the heap, int then each element is copied separately, and the transfer constructor is the resource that the pointer to the parameter directly takes over, and the efficiency is set! It is important to note that the transfer constructor argument must be a right value, typically a temporary object, such as the return value of the function, which is generally destroyed after the line code, and the transfer constructor can be used to prolong its lifetime. At the same time there was avoidance of reopening the array. For the transfer constructor in the above code, it is necessary to analyze it in detail:

Demo (demo&& lre): Arr (Lre.arr), Size (lre.size) ({lre.arr=null;}

lreis a right value reference that indirectly accesses the resource of the argument (the temporary object) to complete the resource transfer, and lre the bound object (must) be the right value, but it lre is the left value;

Because lre it is a local object of a function, " lre.arr=NULL " is necessary, otherwise the function will still release the resource when it is destroyed by calling the destructor lre , and the transferred resource will be recovered by the system.

4. Move () function

The example in 3 is not a panacea, the Demo (demo&& lre) argument must be a right value, sometimes a left value is about to reach the lifetime, but still want to use the transfer semantics to take over its resources, then need a move function.

std::movefunction defined in the standard library <utility>, its role is to force the value of the left to the right to use, from the implementation of the std:move equivalent, it is static_cast<T&&>(lvalue) shown that the transformation of the left value of its own lifetime and left-valued attributes have not been changed, which is similar to const_cast function. So move the argument is supposed to be the left value of the impending lifetime, otherwise it may have a negative effect.

5. Perfect Forwarding (perfect forwarding)

Perfect forwarding refers to a set of arguments "perfectly" passed to the formal parameter, which means that the property of the parameter is invariant const to the left-right value attribute, for example, when the function wraps, the func function has the following overloads:

void func (const int);
void func (int);
void func (int&&);

If you want to wrap them inside a function cover to implement:

void cover (typename para) {
  func (para);
}

A function that can call a corresponding type within a different argument seems to have cover only cover been overloaded by the function, which makes the code omissions, the other way is to use a function template, but before C + + 11, the function template that implements the function can only be passed by value, as follows:

Template<typename t>
void cover (T para) {
  ...
  Func (para);
  ...
}

However, if a large object is passed, and the efficiency problem is caused, it is necessary to use the reference pass to implement the perfect match of the real parameter (the const perfect match between the parcel attribute and the left-right value attribute), using the newly introduced C + + 11 reference Folding rule:

function parameter after type derivation of function parameter T

t& a& a&
t& a&& a&
t&& a& a&
t&& a&& a&&

Therefore, for the function wrapper requirements for the preceding precedent, the following template can be used to resolve:

Template<typename t>
void cover (t&& para) {
  ...
  Func (static_cast<t &&> (para));
  ...
}

If a left-valued reference is passed in, the forwarding function is instantiated as:

void func (t& && para) {

  func (static_cast<t& &&> (para));

}

Apply a reference collapse to:

void func (t& para) {

  func (static_cast<t&> (para));

}

If a right value reference is passed in, the forwarding function is instantiated as:

void func (t&& &¶) {

   func (static_cast<t&& &&> (para));

Applying a reference collapse is:

void func (t&& para) {

  func (static_cast<t&&> (para));

}

For the above static_cast<T&&> , it works only para when it is deduced as a reference to the right, because it para is the left value (the right reference is the left), so it needs to be converted to a right value and then passed in func , C + + 11 defines a std::forward<T>function to achieve the above behavior,

So the final version is

Template<typename t>

void cover (t&& para) {func (Forward (forward<t>

  )));

std::forwardWith a static_cast<T&&>(para) slightly different implementation

std::forwardThe use of the function is forward<T>(para) that if T is a left-value reference, it para will be converted to T the left value of the type, otherwise it para will be converted to the T type right value

Summarize

The above is about c++11 in the right value reference, transfer semantics and perfect forwarding all the content, this article introduces very detailed, I hope that the study of everyone can help.

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.