自我分配有用吗?

apa*_*ara 24 c++ assignment-operator

众所周知,至少在该类具有非POD成员时,在实施分配操作员时必须防止自我分配。通常它是(或等效于):

Foo& operator=(const Foo& other)
{
  if (&other == this)
     return *this;
  ... // Do copy
}
Run Code Online (Sandbox Code Playgroud)

不自动插入自我分配保护的原因是什么?是否存在用例中自我分配完成一些琐碎且实际有用的事情?

Foo& operator=(const Foo& other)
{
  if (&other == this)
  {
    // Do something non-trivial
  }
  else
  {
    // Do copy
  }
  return *this;
}
Run Code Online (Sandbox Code Playgroud)

现在总结答案和讨论

看起来非平凡的自我分配永远不会真正有用。提出的唯一选择是放置一个assert,以便检测一些逻辑错误。但是也有像a = std::min(a, b)这样的非常合理的自我分配案例,因此,即使此选项也是非常可疑的。

但是,平凡的自我分配有两种可能的实现方式:

  1. 如果不采取任何措施&other == this。始终可以工作,尽管由于额外的分支可能会对性能产生负面影响。但是在用户定义的赋值运算符中,几乎必须始终明确进行测试。
  2. 将每个成员复制到自己。这是默认情况下完成的操作。如果成员也使用默认的赋值运算符,则它可能会更快,因为它不需要额外的分支。

我仍然不明白为什么C ++标准不能在用户定义的赋值运算符中保证这一点&other != this。如果不希望分支,请使用默认运算符。如果要重新定义操作员,则仍然需要进行一些测试...

Nic*_*las 19

仅当被跳过的代码应用于自身时很危险时,才需要自分配保护。考虑一下您有一个用户提供的赋值运算符的情况,因为每个单独的对象都有某种您不想复制的标识符。好吧,您可以在自我分配的情况下“复制”其他值。因此,插入一个无形的自指派测试只是添加一个毫无意义且可能代价高昂的条件分支。

因此,自我分配并不是有用的。关于自我分配,并不总是需要保护。

此外,如果您未明确要求,C ++通常不喜欢将类似的代码添加到您的代码中。通常是根据整个功能而不是功能的一部分完成的。当您将要销毁的对象放在堆栈上时,甚至要求在块末尾进行析构函数调用。

  • @VTT:帖子的第二句话是“不自动插入自我分配保护的原因是什么?” 原则性问题之所以存在,是因为假设如果对自赋值的概念没有任何实用性的话,这种*自动保护将会存在。我的帖子反驳了这一假设,一旦反驳,这个问题就变得无关紧要了。 (6认同)
  • OP正在询问一种情况,当自我分配很有用时,而不是在询问是否需要自我分配保护或何时应该实施自我分配保护。同样,我也不得不不同意*“只有在被跳过的代码应用于自身时很危险的类型,才需要自我分配保护。” *即使自我分配本身对发现问题完全没有害处,这种检查还是很有帮助的*在调用代码中*。像`foo [i] = foo [i]`这样的错别字而不是`foo [i] = foo [j]`或类似的问题经常发生。 (2认同)

dav*_*bak 18

有可能发生这种情况的算法。

  1. 您知道lhs和rhs可能是相同的,但是执行分配比检查要简单得多。例如,考虑a = std::min(a,b);-比起更简单,也许更容易理解if (a > b) a = b;-现在考虑相似事物的更复杂示例。

  2. 您可能不知道lhs和rhs是否相同,因为它们可能是从其他地方传入的。

这些可能发生的算法并不罕见。

  • 问题是关于“非平凡”的自我分配。 (2认同)