在赋值运算符中移动语义 - 副作用,破坏

时间:2016-04-28 20:43:55

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

Forcing Move Semantics

  

所以从某种意义上说,我们已经进入了地狱的世界   这里的非确定性破坏:已经为变量赋值,   但以前由该变量持有的对象仍在那里   某处。 只要破坏该对象就可以了   没有任何外界可见的副作用。但是   有时候析构函数会产生这样的副作用。一个例子是   在析构函数中释放一个锁。因此,任何一部分   应该执行具有副作用的对象的破坏   显式地在副本赋值的rvalue引用重载中   操作者:

X& X::operator=(X&& rhs)
{

  // Perform a cleanup that takes care of at least those parts of the
  // destructor that have side effects. Be sure to leave the object
  // in a destructible and assignable state.

  // Move semantics: exchange content between this and rhs

  return *this;
}

我认为l值的原始对象通常会被破坏 - 最终 - 在非分配情况下。

但是,在赋值运算符中,为什么要进行相同的行为?

2 个答案:

答案 0 :(得分:0)

嗯,你必须做你的家务:你有责任将旧的对象修改为(安全的)可破坏的状态(如果你很好,那么甚至是一个特别有效的对象状态)。一切都有成本(甚至移动语义)。

E.g。对于典型的矢量实现:

V& V::operator=(V&& old){
    auto trash = this->data;
    this->data = old.data;

    //cleanup
    delete[] trash;
    old.data = nullptr; // expecting delete[] of the destructor of old
}

您支付了三笔额外的作业(可以使用单个swap()技巧进行优化)并给您自己带来轻微的不便。你避免了大概10000次弃权。值得,不是吗?

此外,如果您在析构函数中使用危险的副作用(您不应该这样做),这不是您遇到的唯一问题。如果你觉得你的班级很危险,你也可以禁用你的移动任务。

答案 1 :(得分:0)

在仔细阅读上一段后,我看到了&#39;答案:当你在析构函数中有副作用时,你希望能够控制这些副作用何时发生。如果你没有在赋值运算符中显式地破坏原始的lhs对象,那么你无法直接控制它的析构函数何时被调用;稍后添加一些代码可能会延长该对象的生命周期。为什么这有关系?就像链接所说的那样,如果你的对象只是像Queue<int>这样的数据,那么谁会关心它何时被破坏。但是,如果您的对象持有锁或其他影响其他对象的资源,那么您希望释放所述资源是确定性的。