我在这里读到接受的答案:
[a] 不会为显式声明移动构造函数或移动赋值运算符的类生成复制构造函数和复制赋值运算符
我确实注意到(g++ 4.7.2),如果你定义一个移动构造函数,它将与例如push_back()
一起使用,而如果你所做的只是= delete
复制构造函数,你不会得到一个隐式移动构造函数 - 你会得到一个错误。 [...这让我想知道,如果您不明确执行任何操作,实际上使用了哪一个(移动或复制)......]
但是,此联机参考不会对定义移动构造函数时未隐式定义的复制构造函数做出相同的显式承诺。
所以我的问题是,标准(包括"或")是否保证了第一个报价? 对于一些需要显式析构函数的类,我更喜欢只用一个移动构造函数和一个(已删除的)移动运算符来完成"五法则",并依赖于未定义的隐式复制方法。 如果我不能依赖它,那么我将不得不明确地=delete
它们 - 但这是很多潜在的冗余内容。
所以我的问题是,标准(包括"或")是否保证了第一个报价?
是的,您的第一个报价由标准保证。
引用标准(草案 n3690):
12.8 复制和移动类对象 [class.copy]
7/如果类定义没有显式声明复制构造函数,则隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数定义为已删除;否则,它被定义为默认值 (8.4)。如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况。
一个有趣的后续问题是为什么?
C++98年是三法则:
如果定义以下任何一项,则应定义所有三个:
- 破坏者
- 复制构造函数
- 复制赋值运算符
创建此经验法则是因为许多人只想着释放析构函数中保存的资源,而忘记了这种特殊行为对副本的影响。
当C++11即将到来时,许多人认为这个问题是由语言提供的默认定义引起的,事后看来,最好不要默认提供它们。当然,C 默认提供它们(用于struct
),所以...
。一些成员建议,事实上,三法则可由编译器强制执行;另一些人认为,三人法则可由编纂者执行。或者至少,由于更改现有行为可能会破坏现有代码,因此每当谈论移动构造函数或移动赋值运算符(这保证新的 C++11 代码)时,编译器都可以强制执行三法则的挂件。
五法则:
如果定义以下任何一项,则应定义所有五个:
- 破坏者
- 移动构造函数
- 移动赋值运算符
- 复制构造函数
- 复制赋值运算符
因此,几乎完全实现为:
- 如果定义移动构造函数或移动赋值运算符,则会隐式删除其他 4 个方法(除非您提供它们)
- 如果定义析构函数、复制构造函数或复制赋值运算符,则会隐式删除移动构造函数和移动赋值运算符(除非您提供它们)
由于与现有 C++98 代码的向后兼容性原因,第二条语句略有不完整(该代码应编译为 C++11,而不会更改行为)。