【问题标题】:move semantics inside assignment operator - side effects, destruction在赋值运算符中移动语义 - 副作用,破坏
【发布时间】:2016-04-28 20:43:55
【问题描述】:

Forcing Move Semantics

所以从某种意义上说,我们已经漂入了冥界 这里的非确定性破坏:一个变量已分配给, 但是该变量以前持有的对象仍然存在 某处。 只要销毁该对象就可以了 没有任何外界可见的副作用。但是 有时析构函数确实有这样的副作用。一个例子是 释放析构函数内的锁。因此,任何部分 应该执行具有副作用的对象破坏 在复制赋值的右值引用重载中显式 运营商:

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;
}

我知道左值的原始对象通常在非赋值情况下被破坏 - 最终 - 。

但是,在赋值运算符中,你为什么想要同样的行为?

【问题讨论】:

  • 有什么问题?
  • @KerrekSB 粗体字。
  • 考虑unique_ptr<T>;如果您有其中 2 个,并且您将一个分配给另一个,您是否不希望目标 unique_ptr<T> 在它拥有源 T 的所有权之前删除它拥有的 T
  • @Praetorian 但你不只是交换 Ts 吗?所以 rhs 只会承担责任吗?
  • 你可以那样实现它,但你为什么要这样做?赋值与交换的语义不同,大多数人不会期望你的赋值运算符表现得那样。

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


【解决方案1】:

好吧,你必须做你的家务:你有责任将旧对象修改为(安全的)可破坏状态(如果你很好,甚至可以修改为一般有效的对象状态)。一切都是有代价的(甚至是移动语义)。

例如对于典型的向量实现:

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 个任务。值得,不是吗?

此外,如果您在析构函数中使用危险的副作用(您不应该这样做),这将不是您遇到的唯一问题。如果您认为这对您的班级有危险,您也可以禁用您的移动作业。

【讨论】:

  • 为什么不能交换所有权?为什么V&& old 不能仅仅承担 lhs 资源的所有权?
  • @Adrian 这是你可以做到的一种方式
  • @vu1p3n0x 好吧,我想了解是否有多种有效的方法可以做到这一点,哈哈。
  • Also if you use dangerous side-effects in destructors (which you shouldn't) - 原始消息来源说在析构函数中具有副作用很好:“只要该对象的破坏没有任何外部世界可见的副作用,这很好。但有时析构函数确实有这样的副作用。一个例子是在析构函数中释放锁。”
  • 我说危险副作用。例如。对象拥有的动态内存很好(如示例中所示)。
【解决方案2】:

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

【讨论】:

  • 让我知道答案是否应该重新措辞。我知道我基本上重新措辞了链接的段落,但对我来说这有助于理解。
  • 你想多了。移动分配首先是复制分配的优化,因此它们之间不应该有外部语义/行为差异(除非你有原因 - 比如像swap()实现风格的过度优化和利用b进行垃圾处理)。实际上这篇文章是错误的,因为这同样适用于复制分配。与其销毁a 的资源,不如将其传递给某个垃圾回收池以便稍后删除。
猜你喜欢
  • 2011-11-19
  • 1970-01-01
  • 2017-11-21
  • 1970-01-01
  • 2021-04-05
  • 1970-01-01
  • 1970-01-01
  • 2016-03-02
  • 2020-05-16
相关资源
最近更新 更多