右值引用
右值引用
左值:表达式结束后依然存在的持久对象
右值:表达式结束后不再存在的临时对象
如果可以对表达式取地址,则为左值。否则为右值。
C++11中,右值包含两个概念:
- 将亡值:将要被移动的对象,T&&函数返回值,std::move返回值和转换为T&&的类型的转换函数的返回值。
- 纯右值:非引用返回的临时变量,运算表达式产生的临时变量,原始字面值,lambda表达式
纯右值完成了相应的赋值构造对其值进行复制后,就被析构了,降低了程序的效率。C++11提供了右值引用及移动构造函数,提高效率。
右值引用的生命周期:只要该变量还活着,右值临时量会一致存在。左值引用不能接受右值。但T&&可以使用左值初始化(发生自动类型推导的时候:函数模板的类型自动推导,或者auto)。
void f(std::vector
这里既有推断类型T,也有确定类型vector,但是是右值,因为调用到f的时候,推断类型已经确定了。
tmplate
void f(const T&& param);
param是右值引用,因为有const
引用折叠:
- 所有的右值引用叠加到右值引用上还是右值引用
- 所有的其他引用类型之间的折叠都将变为左值引用
左值和右值是独立于他们的引用类型的,右值的引用类型可能为左值也可能为右值。(T&&)
编译器会将已命名的右值引用视为左值,未命名的左值引用视为右值。例程:《深入应用C++11》P69
右值引用可以优化性能,避免深拷贝:
深拷贝代价很大,临时变量使用很不必要。
移动构造:
A(A&& a) :m_ptr(a.m_ptr)
{
...
}
再写个正常的深拷贝,这样临时值就调用浅拷贝,避免了额外的拷贝,提高了性能。
注意一般提供移动构造函数的同时还提供拷贝构造函数来保证安全。
引用限定符:
引用限定符可以是&,也可以是&&,分别指出this可以指向一个左值或者右值。类似const。
右值和左值引用的区别主要就是用拷贝还是引用
T&& Value() &&// 阻止右值赋值发生,使右值赋值报错
std::move
如果用左值初始化右值引用,这是不合法的,编译器会报错。
std::move可以将右值转化为左值,转移对象的所有权,没有内存拷贝。