c++11--rvalue Reference

Source: Internet
Author: User

1. Left and right values

An lvalue is a persisted object that persists after an expression ends, and an rvalue is a temporary object that no longer exists at the end of an expression.
In C++11, the right value is divided into two types: the Dead value (Xvalue, expiring value), and the other is the pure right value (Prvalue, pure rvalue). A temporary variable returned by a non-reference, a temporary variable produced by an operation expression, a primitive literal, and a lambda expression are all pure-right values, and the dead value is a new, c++11-related expression, such as the object to be moved, the t&& function return value, and std: The return value of the move return value and the conversion function of the type converted to t&&.

2. Lvalue Reference

An lvalue reference is a type that refers to an lvalue, and is divided into constant lvalue references and a very good lvalue reference. Where a constant Lvalue reference can reference a constant lvalue, a very left value, a constant right value, a very good right value, and a very good lvalue reference can only reference a very important lvalue .

    int x = 1;    const int y = 2;    int& p1 = x;    int& P2 = y; Error, a very constant Lvalue reference cannot reference const    Const int& p3 = x;    Const int& P4 = y;

3. Rvalue reference

C++11 adds an rvalue reference type that implements a reference to an rvalue, marked as T&& Because the right value is not named, it can only be found by reference.

rvalue Reference extends the lifetime of the right value
Lvalue references and rvalue references must be initialized immediately at the time of declaration, because the reference itself does not own the memory of the bound object, but only an alias for that object. With the declaration of the Rvalue reference, the right value is again "reborn," whose life cycle becomes as long as the life of the Rvalue reference type variable , and as long as the variable is alive, the right-value temporary amount will survive forever.

Using rvalue references to extend the lifetime of the right value avoids the construction and destruction of some temporary objects, which improves performance. Like what:

Class A{public:    A () {        cout << "construct ..." << Endl;    }    ~a () {        cout << "Destruct ..." << Endl;    }    A (const a&a a) {        cout << "Copy construct ..." << Endl;    } Private:}; A Geta () {    return a ();} int main () {    A A = Geta ();    return 0;}

The above code, if the compiler is forbidden to automatically do Rvo optimization, completely respect the syntax rules of C + +, the output of the program is

where the A () function inside the Geta () function generates an internal object obj1 the constructor is called, and when the function returns, the temporary object Obj2 copies the contents of the inner object through the copy constructor; After the function returns, the internal object obj1 calls the destructor to destroy; By calling the copy constructor, a copy of the Obj2;a assignment ends, the OBJ2 calls the destructor to destroy; at the end of the program, a calls the destructor to destroy.

During this whole process, the temporary object Obj2 is constructed and geta when the function is called, resulting in unnecessary waste. In c++98/03, you can extend the lifetime of a temporary object by const A& a = GetA() assigning the temporary object obj2 to a constant lvalue reference a, and in c++11, you can also extend the lifetime of the temporary object (the right value) when the function returns by using an rvalue reference instead of a = Geta () Destroy it at the end.

where the A () function inside the Geta () function generates an internal object obj1 when the constructor is called, and when the function returns, the temporary object Obj2 copies the contents of the inner object through the copy constructor; After the function returns, the internal object obj1 calls the destructor to destroy; & a = Obj2 or a&& a = Obj2, at this point the reference is initialized, there is no construction and destruction of the object, and when the program ends, Obj2 (that is, a) is destructor.



4. Assignment of t&&

(1) left and right values are independent of their category, rvalue reference types may be lvalue or rvalue
(2) auto&& or function parameter type automatic derivation of t&& is an undetermined reference type, called Universal Reference, which may be an lvalue reference type or an rvalue reference type, depending on the type of value being initialized.
(3) All rvalue references superimposed on rvalue references are still an rvalue reference, and the other reference overlays are lvalue references. When t&& is a template parameter, an lvalue is entered, and it becomes an lvalue reference, and the right value becomes a named Rvalue reference when you enter an rvalue.
(4) The compiler treats a named Rvalue reference as an lvalue, and an unnamed rvalue reference as an rvalue.

左值和右值是独立于他们的类别的,右值引用类型可能是左值也可能是右值 4.1
int && a = xxxx; the type of a in itself is an rvalue reference, but it is a named variable, an Lvalue

    int &&var1 = 10; VAR1 is an rvalue reference    auto&& var2 = var1;//var2 is now a universial reference, but because VAR1 itself is an lvalue, var2 is an lvalue reference    int W1, W2;    auto&& V1 = W1; Rvalue references    decltype (w1) && v2 = W2;//int &&v2 = w2;//When an rvalue reference is initialized to an lvalue, an error!!

4.2 auto&& 或者函数参数类型自动推导的T&&是一个未定的引用类型,被称为universal reference, 
它可能是左值引用类型也可能是右值引用类型,取决于初始化的值类型。

    auto&& a = 10; A is initialized directly by a right value, then A is an rvalue reference type    int x =;    auto&& b = x; b is initialized by an lvalue, B is an lvalue reference type    template<typename t>    void func (t&& a) {    cout << a << Endl;    }    ....    Func (10); Initialized by an rvalue, A is an rvalue reference type, a type is int&&    int x = ten;    Func (x); Lvalue reference type, A is int&!!!!!    void f (std:vector<t>&& param); It is important to note here that both the derivation type T and the type vector are determined .... In the actual    //application, before calling the function, the inferred type T in,vector<t> has been determined, so there is no type push    /or param to rvalue reference when the F function is called    template< Typenmae t>    void f (const t&& param) {//There is a type deduction here, but is still an rvalue reference because of a const qualification    }

That is, the rvalue operator && only when auto &&/t&&, and without CV qualifier, need to infer the specific lvalue or rvalue reference, otherwise all are rvalue references.

所有的右值引用叠加到右值引用上仍然是一个右值引用,其他引用叠加都为左值引用。 4.3
当T&&为模板参数时,输入左值,它将会变成左值引用,而输入右值时则变为具名的右值引用。

Reference Folding
Due to the existence of an undetermined reference type of t&&, when it is used as a parameter, it may be initialized by an lvalue reference or an rvalue-referenced parameter, when the type-derived t&& type is changed, compared to the rvalue reference (&&). This change becomes a reference folding.

    typedef const INT T;    typedef t& TR;    TR V

the definition of TR Definition of v actual type of V
t& TR V t&
t& tr& V t&
t& tr&& V t&
t&& TR V t&&
t&& tr& V t&
t&& tr&& V t&&

Thus, it can 所有的右值引用叠加到右值引用上仍然是一个右值引用,其他引用叠加都为左值引用。 be seen

4.4 编译器会将已命名的右值引用视为左值,而将未命名的右值引用视为右值

    void print (int& i) {        cout << "Lvalue" << i << Endl;    }    void print (int&& i) {        cout << "rvalue" << i << Endl;    }    Void forward (int&& i) {        print (i);    }    Forward (10); 10 is the right value, and after entering forward, 10 becomes i,i as a variable and becomes the left value.    ///Therefore, output "lvalue" << i << Endl;

5. Rvalue reference optimizes performance to avoid deep copy

For classes that contain heap memory, you need to provide a deep copy of the copy constructor, which, if you use the default constructor, will cause the heap memory to be deleted repeatedly.

Class A{public:    A (): m_ptr (new int (0)) {};    ~a () {        delete m_ptr;    } Private:    int *m_ptr;}; A Get (BOOL flag) {    a A;    A b;    if (flag)        return A;    else        return b;} int main () {    A A = Get (false);   The default copy constructor is simply to assign the m_ptr    //delete m_ptr when the B inside the Get function is destroyed, and when the program finishes, a destructor deletes m_ptr, both m_ptr the same. Causes repeated destruction of memory    return 0;}

If a deep copy is provided for the copy constructor of the class, a large amount of memory copy is generated when the program produces the temporary object, which degrades performance. You can use 移动构造函数 the improvements at this time.

Class A{public:    A (): m_ptr (new int (0)) {};    A (const a& a): m_ptr (new int (*a.m_ptr)) {}; Copy of deep copy constructor    a (a&& a): M_ptr (a.m_ptr) {    //move constructor        a.m_ptr = NULL;    }        ~a () {        delete m_ptr;    } Private:    int *m_ptr;}; A Get (BOOL flag) {    a A;    A b;    if (flag)        return A;    else        return b;} int main () {    A A = Get (true);//Call Move constructor    a b = A;         Call copy constructor    return 0;}

Using the move constructor, the parameter is an rvalue reference type parameter a&&, there is no deep copy, only shallow copy, avoids the shallow copy to the temporary object, improves the performance. The a&& here is used to establish a branch based on whether the parameter is an lvalue or an rvalue, and if it is a temporary value, the move constructor is selected, otherwise the copy constructor is selected .
When the copied source object is temporary, the move constructor is called, which moves the resource of the original temporary object to the destination object of the copy, and the resource of the source object is empty. Then, the source object is refactored and the resource has been transferred to the destination object.

In addition to using the move construct supplemental copy construct, you can also use the move assignment operator instead of the copy assignment operator.

Class A{public:    A (): m_ptr (new int (0)) {};    A (const a& a): m_ptr (new int (*a.m_ptr)) {}; Copy of deep copy constructor    a (a&& a): M_ptr (a.m_ptr) {    //move constructor        a.m_ptr = NULL;    }    a& operator= (const a& A) {        m_ptr = new int (*a.m_ptr);    }    a& operator= (a&& A) {        m_ptr = a.m_ptr;        A.m_ptr = NULL;    }    ~a () {        delete m_ptr;    } Private:    int *m_ptr;}; A Get (BOOL flag) {    a A;    A b;    if (flag)        return A;    else        return b;} int main () {    A A = Get (true);//Call Move constructor    a b = A;         Call copy constructor        a = Get (false);//Call the Move assignment operator    a = b;  Call copy assignment operator    return 0;}


The above adds a move version of the constructor and assignment function, which has some effect on the original class: If the move version of the constructor is provided, the default constructor is not generated. In addition, the compiler will never automatically generate a move version of the constructor and assignment functions, they need to be explicitly added manually.
When a move version of the constructor and the overloaded form of an assignment function is added, which overloaded version should a function call use? The following are the 3 rules listed according to the priority of the decision:
(1) A constant value can only be bound to a constant reference and cannot be bound to a very mass reference
(2) The Lvalue precedence is bound to an lvalue reference, and the right value is first bound to the Rvalue reference
(3) A very high value is first bound to a very high number of references

Reference

Http://www.cnblogs.com/hujian/archive/2012/02/13/2348621.html

+

c++11--rvalue Reference

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.