C++左值和右值及其引用以及move函数

1、左值和右值

        判断依据:可以对表达式取地址&的为左值,否则为右值。

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

 

2、右值引用

引入原因:

        在某些情况下,对象拷贝后就立即被销毁。这些情况下,移动而非拷贝对象会大幅度提升性能。因此,在C++11中引入了右值引用。

        右值引用必须绑定到右值的引用。通过&&而不是&来获得右值引用。右值引用的一个重要特性——只能绑定到一个将要销毁的对象。因此,可以自由地将一个右值引用的资源”移动”到另一个对象中。

        类似任何引用,一个右值引用也不过是某个对象的另一个名字而已。对于常规引用(为了与右值引用区分开来,可以称之为左值引用(lvalue reference)),不能将其绑定到要求转换的表达式、字面常量或是返回右值的表达式。右值引用有着完全相反的绑定特性:可以将一个右值引用绑定到这类表达式上,但不能将一个右值引用直接绑定到一个左值上

例:

int  i = 42;
int  &r = i;					// 正确:r引用i
int  &&rr = i;					// 错误:不能将右值引用绑定到左值上
int  &r2 = i * 42;				// 错误:i * 42为右值
const  int  &r3 = i * 42;		        // 正确:可以将一个const的引用绑定到右值上
int  &&r2 = i * 42;				// 正确:右值引用可以绑定到右值上

 

注:左右值例子

左值:返回左值引用的函数,连同赋值、下标、解引用和前置递增/递减运算符等。

右值:返回非引用类型的函数,连同算术、关系、位以及后置递增/递减运算符等。

 

3、左值持久:右值短暂

        观察左右值表达式可知:左值有持久的状态,而右值要么是字面常量,要么是在表达式求职过程中创建的临时变量。

        由于右值引用只能绑定到临时对象,可知所引用的对象是将要销毁的,该对象没有其他用户。这意味着:使用右值引用的代码可以自由的接管所引用的对象的资源。

注:

变量是左值,不能将一个右值引用直接绑定到一个变量上,即使这个变量是右值也不行。

例:

int  &&rr1 = 42;		// 正确:字面常量是右值
int  &&rr2 = rr1;		// 错误:表达式rr1是左值

 

4、标准库move函数

        虽然不能将一个右值引用直接绑定到左值上,但是可以显式的将一个左值转换为对应的右值引用类型。可以使用move库函数来获得绑定到左值上的右值引用,该函数在utility中。

        move是将对象的状态、所有权从一个对象转移到另一个对象,知识转移,没有内存的搬迁或者内存拷贝。从实现上讲,std::move基本等同于一个类型转换:static_cast<T&&>(lvalue);

例:

int  &&rr1 = 42;
int  &&rr3 = std::move(rr1);

注:一般使用move函数时是用std::move,而非直接使用move。因为如果我们在程序中也定义了一个接受单一形参的move函数,则不管形参是什么类型,引用程序的move函数都将于标准函数的版本冲突。


版权声明:本文为King_weng原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。