C++11 引入右值和移动语义,其中std::move()
是不可或缺的。现在我们才看看std::move()
是这么实现的。
remove_reference
在分析std::move()
之前,先看看remove_reference
,下面是remove_reference
的实现:
template <class T>
struct remove_reference {
using type = T;
};
// 特化版本
template <class T>
struct remove_reference<T&> {
using type = T;
};
template <class T>
struct remove_reference<T&&> {
using type = T;
};
remove_reference
的作用是去除T
中的引用部分,只获取其中的类型部分。无论T
是左值还是右值,最后只获取它的类型部分。
std::move() 实现
借助remove_reference
,std::move()
的实现如下:
template <class T>
typename tinySTL::remove_reference<T>::type&& move(T&& t) noexcept {
using return_type = typename tinySTL::remove_reference<T>::type&&;
return static_cast<return_type>(t);
}
在这段实现看来,实际上std::move
并没有做什么工作,只是做了类型转换,将t
转化为右值。
t 为右值
当t
为右值时,甚至都可以不用做类型转换,直接返回即可。
t 为左值
当t
为左值的时候,可以作为参数传进std::move()
吗?可以的,因为如果一个函数模板参数类型为T&&
,其中T
是需要推到的类型,那么T&&
表示万能引用。万能引用实际用到的技术是引用折叠。
引用折叠的规则可以概括为:
- X& &、X& && 和 X&& & 折叠成 X&;
- X&& && 折叠成 X&&。
如果T = X&
是左值引用,则展开后得到了X& &&
,根据上面的规则,最终得到X&
。
如果T = X&&
是右值引用,则展开后得到了X& &&
,根据上面的规则,最终得到X&&
。
所以,当t
为左值或者左值引用时,进过引用折叠,得到的类型是T&
。最后就是将左值转换为右值并返回了。
总结
实际上,std::move()
并不会move
,仅仅做了类型转换而已。真正的移动操作是在移动构造函数或者移动赋值操作符中发生的。std::move()
可以应用于左值,但这么做要谨慎。因为一旦“移动”了左值,就表示当前的值不再需要了,如果后续使用了该值,产生的行为是未定义。
打广告
我“写”了一个低效的STL子集,放在Github上,欢迎大家交流指导。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。