右值引用
什么是左值和右值:左值实指表达式结束后依然存在的持久对象,右值是指表达式结束后就不存在的临时对象。
区分左值和右值的便捷方法:看能不能对表达式取地址,如果能,为左值,如果不能,则为右值。所有的具名变量或对象都是左值,而右值不具名。
在C++11中右值由两个概念构成:
1.一个是纯右值,比如,非引用返回的临时变量,运算表达式产生的临时变量,原始字面量和la’mbda表达式等都是纯右值。
2.另一个则是将亡值,而将亡值是C++11新增的与右值引用相关的表达式,比如将要被移动的对象、T&&函数返回值、std::move返回值和转换为T&&的类型的转换函数的返回值
例子:
int main()
{
int a=10;
int&& x1=a; //错误
int&& x2=10;
const int&& c=10;
Object obja(10);
Object objb=obja; //错误
return 0;
}
C++11中所有的值必属于左值、将亡值、纯右值三者之一,将亡值和纯右值都属于右值。
C++11增加了一个新的类型,称为右值引用,标记为T&&。
右值引用就是对一个右值进行引用的类型。一位右值不具名,所以我们只能通过引用的方式找到它。
无论声明左值引用还是右值引用都必须立即进行初始化,因为引用类型本身并不拥有所绑定对象的内存,只是该对象的一个别名。通过右值引用的声明,该右值又“重获新生”,其生命周期与右值引用类型变量的生命周期一样,只要变量还活着,该右值临时变量将会一直存活下去
例子:
class Object
{
private:
int val;
public:
Object(int x=0):val(x) {cout<<"construct object"<<endl;}
Object(const Object& obj) :val(obj.val)
{cout<<"copy costruct object"<<endl;}
Object& operator=(const Object& obj)
{
val=obj.val;
cout<<"="<<endl;
return *this;
}
~Object(){cout<<"deconstruct object"<<endl;}
};
Object fun(int a)
{
Object x(a);
return x;//临时对象
}
int main()
{
int a=0;
const int b=10;
Object obj(10);
obj=fun(100);
return 0;
}
其中:
a为左值,0为纯右值;b为左值,10为纯右值。
右值引用存在的价值:
右值引用绑定了右值,让临时右值的声明周期延长了。可以利用这个特点做一些性能优化,即避免临时对象的拷贝构造和析构。
C++11的引用折叠规则:
1.所有右值引用叠加到另一个右值引用上还是一个右值引用。
2.所有其他类型引用的叠加都是左值引用。
如何使左值变为右值呢?
int a=10;
int&& x1=a; //错误
int&& x2=10;
int&& x3 =std::move(x2); //正确
std::move()函数定义在头文件utility中,可以将一个左值转化为右值。