昨天又学习了下右值、move和forward。记录一下学习到的东西:
1、引用退化
左值引用有传染性。左值引用的右值引用或右值引用的左值引用结果都是左值引用,即:
string& &&和string&& &都等于string&
string & & 等于string &
string && &&等于string &&
2、左值和右值是表达式的属性
即存在这个情况:某个变量的类型是右值引用,但变量自己构成的表达式却是左值
3、具名的左值引用和右值引用都是左值,不具名的右值引用是右值
因为有名字的变量,不管是左值还是右值,在你没有明确声明的情况下,默认不会立即销毁,因此不能当右值看待
4、move
不管左值引用还是右值引用,通过move后都换成右值引用
5、forward
std::forward<T>(x)
如果T是string,那么返回string&&;如果T是string&,那么返回string&。返回类型和x类型无关
那为什么叫完美转发呢?和x是左值引用还是右值引用都没有关系!!
关键在于这个T不是固定的,而是由编译器从函数参数上类型推导出来的。
template <typename T>
T&& func(T&& x)
{
return std::forward<T>(x);
}
当用string&调用func时,T的类型推导为string&。由于引用退化,T&&等效于string&,因此返回值也是左值string&。
当用string&&调用func时,T的类型推导为string。因此返回值就是string&&。
从而做到了完美转发。
因此foward的完美转发一定要和模板参数自动推导关联起来使用,单独forward自己是没法完美转发的。
6、使用右值作为函数参数对传统函数进行优化
一般对形如:func(const X& data)的函数进行重载优化:
func(X&& data)
当实参是X&、const X&、const X&&时,调用老的函数。而当实参是X&&时,调用新的函数以获得性能上的提升。
7、默认类型转换
Type&& 可以默认转为Type&、const Type&、const Type&&。因为它的约束是最强的。它的约束包含:
a) 指向一个合法的对象
b) 可以修改
c) 该对象马上将销毁,可以偷窍其数据
而Type&只包含a)、b)两个约束
const Type&&可以默认转为const Type&
Type&只能默认转换为const Type&。如需把它转成Type&&,可以使用std::move
const Type&不能转换成其它三个类型
8、const Type&&没啥存在的意义
马上都要销毁了,还不让人修改,图啥呢?