【发布时间】:2019-10-12 10:51:32
【问题描述】:
众所周知,在实现赋值运算符时,必须防止自赋值,至少当类具有非 POD 成员时。通常是(或等价于):
Foo& operator=(const Foo& other)
{
if (&other == this)
return *this;
... // Do copy
}
没有自动插入自赋值保护的原因是什么?是否存在自我分配做一些重要且实用的事情的用例?
Foo& operator=(const Foo& other)
{
if (&other == this)
{
// Do something non-trivial
}
else
{
// Do copy
}
return *this;
}
现在总结一下答案和讨论
看起来非平凡的自我分配永远不会真正有用。提出的唯一选择是在其中放置一个assert 以检测一些逻辑错误。但也有像a = std::min(a, b) 这样相当合理的自我分配案例,所以即使是这个选项也很可疑。
但是有两种可能的微不足道的自赋值实现:
- 如果
&other == this什么都不做。始终有效,但由于额外的分支可能会对性能产生负面影响。但在用户定义的赋值运算符中,测试几乎总是必须显式进行。 - 将每个成员复制到自身。这是默认完成的。如果成员也使用默认赋值运算符,可能会更快,因为不需要额外的分支。
我仍然不明白为什么 C++ 标准不能在用户定义的赋值运算符&other != this 中保证这一点。如果您不想分支,请使用默认运算符。如果要重新定义运算符,无论如何都需要进行一些测试...
【问题讨论】:
-
这是一个有趣的问题。我什至会说,通常自赋值是某种逻辑错误的指标,使用断言或其他形式的严格检查是有意义的。我绝对可以想象它是无害的,但没有用。
-
好吧,C++ 标准库已经疯狂到可以通过有效的操作重载
<<和>>。也许他们认为有人可能想用=做同样疯狂的事情。 -
条件分支可能会让“check and might do nothing”比“just do it”慢,所以默认不应该做check。
-
我还可以想象您想知道它发生频率的情况,可能是出于性能原因。如果语言要“隐藏”自我分配,这将很难分析。
-
你可能会发现这是一个有趣的阅读:ericniebler.com/2017/03/31/post-conditions-on-self-move