->lvalue 有标识符、可以取地址的表达式:变量、函数或者数据成员的名字;返回左值引用的表达式(++x x= 1 count << ' ' );字符串的字面量("hello")
函数调用时,左值可以绑定到左值引用T&。常量只能绑定到常左值引用const T&
字符串的字面量是一个对象:节省内存,同一份字符串字面量引用的时同一块内存&"hello"是合法的。
->prvalue 没有标识符、不可取地址的表达式,一般也称之为临时对象:返回非引用类型的表达式(x++ x+1 make_shared<int>(42));除了字符串字面量之外的字面量(42 true)
C++11之前右值可以绑定到常左值引用const T&但不能绑定到非常左值引用。C++11引入了右值引用T&&
->如果一个prvalue被绑定到一个引用上,那么他的生命周期则会延长到跟这个引用变量一样长。
※该规则只对prvalue有效,对xvalue无效
->C++11之前,返回一个本地对象意味着这个对象会被拷贝,除非编译器发现可以做返回值优化NRVO named return value optimization,能把对象直接构造到调用者的栈上。
C++11NRVO仍可发生,但是没有NRVO的情况下,编译器将试图把本地对象移动(move)出去,而不是拷贝(copy)。
※手动std::move(obj)会妨碍编译的返回值优化NRVO
->引用塌缩(引用折叠):右值引用叠加到右值引用上是右值引用T&& && -> T&&,其他所有引用类型的叠加都是左值引用T& & T& && T&& & -> T&
模板元编程
template<typename T>
void foo(T&& t) {} // T&&不是右值引用,而是未定引用类型(转发引用) -> 实际类型参考引用折叠
非模板元编程
void foo(int&& v) {} // int&&是明确的右值引用类型
->std::move 将一个左值转换成右值(xvalue)
->std::forward 将一个引用转化为他的类型所对应的值类型。左值引用转换为左值,右值引用转换为右值