C++11中的右值和右值引用

左值和右值:

1. 对一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。

2.  左值具有持久的状态,而右值要么是字面常量(注意字符串常量是左值),要么是在表达式求值过程中创建的临时对象。

3.  返回左值引用的函数、赋值、下标、解引用、前置递增/递减运算符都是返回左值的表达式。(对于前置递增/递减如++a,是将持久对象a加1,然后返回持久对象a本身,所以是左值)

     返回非引用类型的函数、算术、关系、位以及后置递增/递减运算符,都生成右值。(对于后置递增或递减如a++,是先取出持久对象a的一份拷贝,再使持久对象a加1,最后返回那份拷贝,而这份拷贝使临时对象,因此是右值)

4.简单的来说,我们可以通过能不能对表达式取地址来判断是左值还是右值。左值可以取地址,右值则不行。

右值引用:

1. 右值引用只能绑定到一个将要销毁的对象。

2.当右值引用将该类型变量关联到一个将要销毁的对象之后,那么该对象的生命周期将和该变量一样长。如int&& a = getA();函数getA()返回的临时变量或对象的生命周期将和变量a一样长。

3. 非常量左值引用、常量左值引用、非常量右值引用以及常量右值引用的初始化引用规则如下:

          

需要注意的是:对于   int && r1 = 13;是合法的,这是因为对于对象10,是字面常量;对于表达式10,是右值。

4. 要注意右值引用类型的变量本身是一个左值,千万不要将这个变量关联到右值引用上。如

       int && r1 = 42;  //正确,字面常量是右值

       int && r2 = r1; //错误,表达式r1是左值

5. 在发生自动类型推导的时候(如函数模板或者auto关键字),T && t是一个未定的引用类型(universal references)。如果是被一个左值初始化,那么 t 就是一个左值。相反,如果是被一个右值初始化,t 则是一个右值。如下:

     template <typename T>
     void f(T && t) 
     {

            int&& tmp = std::forward<T>(t);
            cout << "t: " << t << endl;
     }    

    //主函数

   f(10);//传入的是右值,因此T && 是右值引用类型,这一句不会报错

   int x = 10;

   f(x);//传入的是左值,因此T && 是左值引用类型,如果这句不注释掉,编译器会报错,证明这条语句调用后的 t 是左值,而左值不能和右值引用关联,所以报错。

注意:上面的std::forward是用来保持参数的实际类型,即为了避免 t 本身是变量(左值),在进入函数体后根据实参初始化后 t 的属性被本身左值属性影响,即无论是用左值初始化还是右值初始化,由于t本身是左值导致在函数体内变成左值。使用std::forward就能保持初始化时的性质。

猜你喜欢

转载自blog.csdn.net/J_H_C/article/details/82288027
今日推荐