左值
可以放在等号的左边和右边,能够取地址
举例 :
- 变量名;
- 函数返回值,或函数传递参数;
- 前置自增、自减(++i,–i);
- 赋值运算或复合赋值运算表达式
右值
只能放在等号右边,不能取地址,不具名。可以区分为C++11之前的纯右值和之后的将亡值
存右值
- 字面值;
- 返回非引用类型的函数;
- 后置自增、自减(i++,i–);
- 算术表达式;
将亡值
C++11 新引入的与右值引用(移动语义)相关的值类型,将亡值用来触发移动构造或移动赋值构造,之后将亡值将调用析构函数。
可以通过std::move、static_cast<T &&>(x);将左值转换为将亡值,以此将资源拷贝变为资源移动。
左值引用和右值引用的区别
顾名思义,左值引用是对左值的引用;右值引用是对右值的引用。但是它们有什么区别呢?
- 首先const 左值引用能指向右值,但有个局限就是不能进行修改;
- 其次右值引用可以通过std::move(v)指向左值(因为move()把左值变成了右值);
- 声明出来的左值引用和右值引用都属于左值。(T &、T && 两者都是左值)。
功能差异
左值引用避免对象的拷贝,通常用于传参和函数返回值;而右值引用是为了实现移动语义和完美转发。
移动语义
对象赋值时,避免资源的重新分配,常应用在STL,以及unique_ptr智能指针的实现中。
完美转发
在函数模板中,可以将自己的参数完美地转发给内部调用的其他函数。其中完美的意思是,不仅准确地转发参数的值,还能被转发参数的左、右值的属性。
#define WANGMEI 1
#if WANGMEI
template<typename T>
void fun(T&& a){
// 引用折叠参数为左值或左值引用,T&&将转化为a&;参数为右值或右值引用,T&&将转化为a&&
fun1(forword<T>a); //此时加上forword<T>实现完美转发
}
#else
template<typename T>
void fun(T&& a){
// 引用折叠参数为左值或左值引用,T&&将转化为a&;参数为右值或右值引用,T&&将转化为a&&
fun1(a);
}
#end if
int main(){
int i = 10;
int&& a = i; //左值引用
int&& b = 1; //右值引用
fun(a); // fun中的fun1传递的a是左值
fun(b);// fun中的fun1传递的b是右值
}