明确定义的移动构造函数是否会消除隐式复制构造函数?

4
我在这里的被接受的答案中读到:

对于一个明确声明了移动构造函数移动赋值运算符的类,不会生成复制构造函数和复制赋值运算符。

我注意到(g++ 4.7.2),如果您定义了一个移动构造函数,它将与例如push_back()一起使用,而如果您只是=delete 复制构造函数,则不会获得隐式移动构造函数 -- 您会收到错误。这让我想知道在没有做任何显式处理的情况下实际使用哪个(移动或复制)......

但是,这个在线参考并没有对于当您定义一个移动构造函数时会隐含定义复制构造函数作出同样明确的承诺。

因此,我的问题是,第一段引用是否由标准(包括"或")保证? 对于一些需要明确析构函数的类,我更喜欢仅使用移动构造函数和(已删除的)移动运算符完成“五大规则”,并依赖于隐式复制方法被定义。 如果我不能依赖它们,那么我将不得不显式地=delete这些函数 -- 但这是很多可能是冗余的工作。


1
那个在线参考资料说:“如果满足以下任何条件,则不会为类T生成隐式复制构造函数。”...“T具有用户定义的移动构造函数或移动赋值运算符”。也许措辞需要改进...现在它说“如果定义为已删除”。 - Cubbi
2个回答

6
我的问题是,第一个引述(包括“或”)是否被标准保证?
是的,你的第一个引述由标准保证。
以下是标准稿(n3690)的引述:
12.8 复制和移动类对象 [class.copy] 7/ 如果类定义没有显式声明复制构造函数,则默认声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数将被定义为删除;否则,它将被定义为默认(8.4)。如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则后一种情况被弃用。

2
一个有趣的后续问题是什么?
在C++98中有三五法则
如果你定义了以下任何一个,都应该定义所有三个:
析构函数 复制构造函数 复制赋值运算符
这个经验法则的出现是因为很多人只考虑了在析构函数中释放资源,而忘记了这种特殊行为对于拷贝操作的影响。
当C++11出现时,许多人认为这个问题是由语言提供的默认定义引起的,并且事后看来最好不要默认提供它们。当然,C默认提供它们(对于结构体)所以...
... 一些人建议实际上可以通过编译器强制执行三五法则;或者至少,由于改变现有行为可能会破坏现有代码,每当涉及到移动构造函数或移动赋值运算符时,编译器都可以强制执行三五法则的补充规定(这保证了新的C++11代码)。
五则法则:
如果定义了以下任何一个方法,就需要定义全部五个方法:
- 析构函数 - 移动构造函数 - 移动赋值运算符 - 复制构造函数 - 复制赋值运算符
因此,实现时几乎完全是这样的:
- 如果定义了移动构造函数或移动赋值运算符,则其他四个方法会被隐式删除(除非您提供了它们)。 - 如果定义了析构函数、复制构造函数或复制赋值运算符,则移动构造函数和移动赋值运算符会被隐式删除(除非您提供了它们)。
第二个陈述略微不完整,是为了向后兼容现有的C++98代码(应该可以编译为C++11而不改变行为)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接