【问题标题】:Why defining a destructor deletes the implicitly defined move assignment operator?为什么定义析构函数会删除隐式定义的移动赋值运算符?
【发布时间】:2015-12-02 12:06:23
【问题描述】:

C++ 标准委员会选择在定义自定义析构函数时删除隐式定义的移动赋值运算符的基本原理是什么?

【问题讨论】:

  • 我不知道,所以我只能猜测:它可能来自rule of 3,当您需要析构函数时,您还需要一个复制和赋值运算符。这也适用于移动运算符

标签: c++ c++11 destructor move-assignment-operator


【解决方案1】:

来自 Scott Meyer 的 Effective Modern C++ Item 17(假设您了解 Rule of Three):

三规则的结果是用户声明的析构函数的存在表明简单的成员复制不太可能适合类中的复制操作。反过来,这表明如果一个类声明了一个析构函数,则可能不应该自动生成复制操作,因为它们不会做正确的事情。 [...]

然而,三法则背后的推理仍然有效,再加上观察到复制操作的声明排除了移动操作的隐式生成,这激发了 C++11 确实不 为具有用户声明的析构函数的类生成移动操作。

【讨论】:

  • 三者的规则只是一组建议,而不是编译器的动作。正如您的帖子引用的那样:“如果一个类声明了一个析构函数,则可能不应该自动生成复制操作”。为什么它变成了“不能自动生成”的移动操作?
  • @nyarlathotep108 预期的问题是一个不正确的隐式复制/移动构造函数,当不需要时。委员会决定通过在这种情况下禁用生成来保护用户免受此潜在问题的影响。
【解决方案2】:

这个想法是,任何默认生成的构造函数(复制构造函数、复制赋值或析构函数)的存在都表明一个类型需要进行某种特殊的资源管理。如果是这种情况,默认的移动操作可能不会做正确的事情。我不确定是否确实出现了默认生成的复制构造函数正常工作但默认生成的移动构造函数失败的示例。

解决方案是默认生成移动操作更安全,特别是因为很容易要求相应的移动操作:只需添加一个= defaulted 实现。无论如何,该类显然已经做了一些特殊的事情(否则将没有析构函数)。

【讨论】:

  • 为什么是移动赋值运算符而不是复制赋值运算符?
  • @nyarlathotep108:历史镇流器。不推荐使用默认的副本分配。
  • @nyarlathotep108:在定义复制构造规则时,没有= default这样的东西。实际上,人们甚至没有想到Rule of Three(这实际上是不正确的:为了强异常安全,有时需要实现赋值运算符,尽管不需要其他结构)。现在更改规则会破坏很多代码。也就是说,正如 KerrekSB 所说,简短的回答是:“历史性镇流器”
  • @nyarlathotep108:当前标准实际上不赞成自动创建复制结构(如果其他任何可用)(参见 D.3 [depr.impldec])。
猜你喜欢
  • 1970-01-01
  • 2018-10-05
  • 1970-01-01
  • 2015-04-17
  • 2020-09-06
  • 1970-01-01
  • 2014-07-09
  • 1970-01-01
  • 2020-06-18
相关资源
最近更新 更多