c++11新标准-右值引用

写在前面

认识右值引用之前,可以先回忆一下左值、右值、左值引用等概念。

左值

左值(lvalue)这一术语来源于C语言,用来指代那些可以用在赋值表达式左侧的东西,例具名对象、在栈和堆上分配的对象或者其他对象的成员,总之就是有存储空间的东西。

int a;	//变量 a 是左值
B b = new B();	//假设B 是一个自定义类,则 b 也是一个左子。
				//若类B 有一个 int类型的成员变量c, 则B::c 也是一个左值。

右值

术语右值(rvalue)也是源于C语言,指的是只能在赋值表达式右侧出现的东西,如字面值和临时对象

int i = 42;		//字面值42 是右值
string s = string("abc");	//匿名临时对象 string("abc") 是右值

左值和右值的区别

  1. 出现位置不同。左值出现在赋值表达式左侧,右值出现在赋值表达式右侧。
  2. 左值持久,右值短暂。左值拥有持久的状态(直到离开声明处的作用域才被销毁);而右值要么是字面常量,要么是临时对象。

归纳:当一个对象被用作返回右值的表达式的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(内存)。

int i = 42;		//变量i 是一个左值, 常量值42 是右值。
int j = i + 1;	//i 被用作返回右值的表达式,使用的是i 的值42,即表达式i + 1 相当于42 + 1,返回的是右值。
i = 50;			//i 被用作左值,用的是对象的身份,即i 指向的内存存储的是 50。

左值引用

左值引用(lvalue reference)指的是必须绑定到左值的引用,通过 & 来获得左值引用。

左值引用的绑定特性:我们不能将左值引用绑定到要求转换的表达式、字面常量或是返回右值的表达式。

int i = 42;		//左值i, 右值42
int& r = i;		//左值引用r, 绑定到左值i 上,即r 引用 i
int& a = 42;	//错误。42是右值(字面常量),左值引用不能绑定到右值上
const int & a = 42;	//正确。可以将一个const 的引用绑定到一个右值上

double b = 3.14;	//声明一个double类型变量,初始值为3.14
int& c = b;		//错误。左值引用不能绑定到要求转换的表达式

int& d = i + 1;	//错误。表达式i + 1 返回右值,而左值引用不能绑定到返回右值的表达式。i*2,i/2等同理

右值引用

为了支持移动操作,新标准引入了一种新的引用类型-右值引用(rvalue reference)。

所谓右值引用就是必须绑定到右值的引用。通过 && 而不是 & 来获得右值引用。

右值引用有一个重要的性质-只能绑定到一个将要销毁的对象。

即:①所引用的对象将要被销毁 ②该对象没有其他用户

右值引用有着和左值引用完全相反的绑定特性。

int&& i = 42;	//正确。绑定到右值的右值引用i

int j = 42;
int&& k = j;	//错误。j 是一个左值

左值引用和右值引用的区别

  1. 绑定对象不同。左值引用只能绑定到左值,不能绑定到右值;右值引用只能绑定到右值而不能绑定到左值。
  2. 绑定对象(左值右值)的生存期不同。
    例:int& b = a; 即左值引用b 绑定到变量a 上,a 是一个变量,其生存期为声明它的作用域。由于右值引用只能绑定到临时对象(int&& = 4),4 相当于int(4),即声明了一个匿名的int类型的对象,该对象在这条语句之后会被销毁。

补充

我们一般的认知是变量是左值,但是变量也可以看作是只有一个运算对象而没有运算符的表达式。

《c++ primer》中对表达式的定义:表达式由一个或多个运算对象组成,对表达式求值将得到一个结果。字面值和变量是最简单的表达式,其结果就是字面值和变量的值。

类似其他任何表达式,变量表达式也有左值/右值属性。变量表达式都是左值,带来的结果就是:我们不能将一个右子引用绑定到一个右值引用类型的变量上。

int&& rr1 = 42;		//右值引用rr1 
int&& rr2 = rr1;	//错误,表达式(这里不以变量称呼rr1)是左值

因为右值是临时对象,而变量是持久的,直至离开作用域时才会被销毁,所以变量是左值。因此我们不能将一个右值引用绑定到一个变量上(左值),即使这个变量是右值引用类型也不行!

你可能感兴趣的:(C++,C++11新标准,c++11)