[C++技法] 右值引用与移动语义
了解右值和右值引用的概念以及移动语义的实现。
右值引用(rvalue reference),是C++11标准提出的一类数据类型。
可用于实现移动语义(move semantic)与完美转发(perfect forwarding)。
右值
何为右值(r-value),说人话就是只能放在等号右边的东西。例如int a = 1
这个表达式中,a
在等号左边,所以a
是左值,而1
是右值。
右值通常为一个表达式,是赋值计算产生临时生成的中间变量。
右值引用
C++中,通常的引用是指左值引用,用符号&
表示,而右值引用符号为&&
。
|
|
在上述代码中,定义了一个对a
的左值引用,但是&
符号不能对1
引用,int &ref = 1
的非法的。
但是可以使用int &&ref = 1
,定义一个对1
的右值引用。
|
|
可以看出来这里的右值引用自身是一个左值(有名字的右值引用自身是左值)。
std::move
std::move
一般理解为移动操作,在PImpl讲过的std::unique_ptr
这个智能指针是禁止拷贝的,这是便可使用std::move
对其进行移动操作。但std::move
的原理是将左值转化为右值,底层操作中并没有实现内存的移动啥的。(如果没理解的话这就是个坑)
|
|
但是和int&& rref = 1
不同的是,此时r_ref
也相当于a
的一个左值引用。同时可以看出std::move
根本没把a
给移掉,因为像int
这样的基本类型std::move
对其是没有影响的。像string
、std::unique_ptr
这样的move
就会变空了。要养成移动后不在使用的习惯
右值引用作函数参数
|
|
单从性能上来看,左右值引用都避免了传参拷贝。
顺带提一下,C++规定 &&
可以自动转化为const&
,所以当形参为void func(int const& v)
时调用func(2)
其实是隐含了一个转换。但右值引用比const
引用更灵活,因为它还是可以修改的。
移动语义
移动构造函数
在PImpl中也可以看到widget
类中移动构造函数的参数为右值引用。
|
|
这样做的好处同样是比用const
引用更加灵活,可以做浅拷贝提升性能。
容器避免深拷贝
STL类大都支持移动语义函数,比如vector
就可以用std::move
避免深拷贝以提升性能
|
|
可移动对象在需要拷贝且被拷贝者之后不再被需要的场景,可以使用
std::move
触发移动语义,提升性能。
其他
std::forward
std::forward
叫做完美转发,和std::move
一样,这货跟转发没半毛钱关系。也是用于类型转换。
它不仅可以把左值转为右值,还可以反过来把右值转为左值。
使用方法:
|
|
这东西使用场景不多,我也不太懂,就不多做介绍了。
更多右值引用技巧可看这个 https://zhuanlan.zhihu.com/p/107445960