4

我在接受的答案中读到

[a] 不会为显式声明移动构造函数移动赋值运算符的类生成复制构造函数和复制赋值运算符

我确实注意到(g++ 4.7.2),如果你定义了一个移动构造函数,它将与例如 一起使用push_back(),而如果你所做的只是= delete复制构造函数,你不会得到一个隐式移动构造函数——你会得到一个错误。 [...这让我想知道如果您没有明确执行任何操作,实际使用的是哪个(移动或复制)...]

但是,此在线参考并没有明确承诺在定义移动构造函数时不会隐式定义复制构造函数。

所以我的问题是,标准是否保证了第一个报价(包括"or")?对于一些需要显式析构函数的类,我更喜欢仅使用移动构造函数和(删除的)移动运算符来完成“五规则”,并依赖未定义的隐式复制方法。如果我不能依赖它,那么我将不得不明确地指出=delete它们——但这是很多潜在的冗余内容。

4

2 回答 2

6

所以我的问题是,标准是否保证了第一个报价(包括"or")?

是的,您的第一个报价由标准保证。

引用标准(草案 n3690):

12.8 复制和移动类对象[class.copy]

7/ 如果类定义没有显式声明复制构造函数,则隐式声明。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数定义为已删除;否则,它被定义为默认值(8.4)。如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况。

于 2013-09-19T13:28:24.687 回答
2

一个有趣的后续是为什么?

在 C++98 中是三法则

如果您定义以下任何一项,您应该定义所有三个:

  • 析构函数
  • 复制构造函数
  • 复制赋值运算符

创建这个经验法则是因为许多人只想释放析构函数中的资源,而忘记了这种特殊行为对副本的影响。

当 C++11 即将到来时,许多人认为这个问题是由该语言提供的默认定义引起的,事后看来,最好不要默认提供它们。当然,C 默认提供它们(for struct)所以......

...有些人建议实际上编译器可以强制执行三法则;或者至少,由于更改现有行为可能会破坏现有代码,因此编译器可以在谈论移动构造函数或移动赋值运算符(这保证新的 C++11 代码)时强制执行三法则的附属物。

五法则:

如果您定义以下任何一项,则应定义所有五项:

  • 析构函数
  • 移动构造函数
  • 移动赋值运算符
  • 复制构造函数
  • 复制赋值运算符

因此几乎完全实现为:

  • 如果您定义移动构造函数或移动赋值运算符,则其他 4 个方法将被隐式删除(除非您提供它们)
  • 如果您定义析构函数、复制构造函数或复制赋值运算符,则移动构造函数和移动赋值运算符将被隐式删除(除非您提供它们)

由于与现有 C++98 代码的向后兼容性原因,第二条语句稍微不完整(应该编译为 C++11 而不会改变行为)。

于 2013-09-19T13:57:34.013 回答