stdmove源码分析

34次阅读

共计 1066 个字符,预计需要花费 3 分钟才能阅读完成。

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_referencestd::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() 吗?可以的,这里用到的技术是引用折叠。
引用折叠的规则可以概括为:

  • X& &、X& && 和 X&& & 折叠成 X&;
  • X&& && 折叠成 X&&。

所以,当 t 为左值或者左值引用时,进过引用折叠,得到的类型是T&。最后就是将左值转换为右值并返回了。

总结

实际上,std::move()并不会 move,仅仅做了类型转换而已。真正的移动操作是在移动构造函数或者移动赋值操作符中发生的。
std::move() 可以应用于左值,但这么做要谨慎。因为一旦“移动”了左值,就表示当前的值不再需要了,如果后续使用了该值,产生的行为是未定义。

打广告

我自己实现了 STL 的部分功能,放在 Github 上,欢迎大家交流指导。

参考

  • 《C++ Primer》第五版
  • std::remove_reference
  • std::move
  • 关于 C ++ 右值及 std::move()的疑问?– 知乎

正文完
 0