是所有基于std :: move()的std :: swap()实现我都看到了错误吗?

时间:2012-07-27 16:01:24

标签: c++ c++11 swap move-semantics move-constructor

  

可能重复:
  What can I do with a moved-from object?

例如,请参阅this code

template<class T> 
void swap(T& a, T& b) 
{ 
    T tmp(std::move(a));
    a = std::move(b); 
    b = std::move(tmp);
} 

只是我,还是这里有错误?如果您move a进入tmp,那么a会无效吗?

即。来自a的{​​{1}}移动分配不应该是位置b的移动构造函数调用吗? 如果没有,那么移动构造函数和移动赋值运算符之间有什么区别?

new

3 个答案:

答案 0 :(得分:9)

当您从对象移出数据时,预期的语义是移动的对象最终处于未指定但有效的状态。这意味着你无法预测对象将处于什么状态,除了它将是一个格式良好的对象。这与“这个物体已经死了,不见了”并不完全相同。将数据移出对象并不会终止对象的生命周期 - 它只是将其状态更改为未指定的状态 - 因此为该对象分配新值是完全安全的。

因此,交换功能的初始版本是安全的。从a移动数据后,该对象保留了一些未指定的“安全但不可预测”的值。移动时,该值将被覆盖,并将其赋值为b。

第二个版本不安全,因为在您尝试在其上构建新对象之前,a的生命周期尚未结束。这导致了不确定的行为。

希望这有帮助!

答案 1 :(得分:6)

a仍然有效。 a内的数据不再可靠。 移动资源时,您不会取消分配a,因此将新资源移至a完全可以。

答案 2 :(得分:5)

移动不会使对象无效。相反,它总体上仍处于有效但不确定的状态。特定班级有额外保证;例如,std::unique_ptr保证从移动后它将为null。

保留有效对象尤其意味着分配给对象是完全正确的,这就是原始代码的作用。

您自己提出的解决方案严重受损:当您在旧对象上放置构造新对象时,旧对象的生命周期结束。但是,如果类的析构函数具有效果,则省略调用析构函数是未定义的行为。

此外,如果你首先正确地调用析构函数,但在构造函数中遇到异常,那么你就会遇到麻烦,因为你现在没有一个需要的有效对象在范围出口处被摧毁。这是关于此主题的related question of mine