显式移动 ctor 是否消除了隐式复制 ctor
Does an explicit move ctor eliminate implicit copy ctor?
我在这里读到接受的答案:
[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,而不会更改行为)。
- 对复制 CTOR 和 CTOR 的未定义引用
- C++ 基本 CTOR 说明 - 为什么不调用赋值/复制构造函数
- C++成功复制动态分配的 obj 而不复制 ctor?
- 给定一个右值,为什么移动ctor比常量复制ctor更匹配
- 在派生类中使用基类复制 CTOR
- 复制 CTOR 与赋值运算符以初始化对象(性能)
- 相同指令的输出不同 - 移动并复制CTOR
- 为什么编译器在调用 move 后选择复制 ctor
- 是否应在调用基本CTOR时复制继承的构造函数
- 复制ctor被称为而不是移动ctor-可以编译器发出警告
- 复制 ctor 与互斥锁作为数据成员
- 为什么移动 ctor 比复制 ctor 慢?
- 是否可以使用 lambda 初始化变量(删除复制 ctor 时)
- 当使用三元运算符并删除移动/复制CTOR时,Visual Studio不执行RVO
- 自 C++17 以来,复制 elision 不需要存在和访问复制或移动 CTOR
- 警告在 std::move'ing 时调用复制 ctor
- 我无法弄清楚的复制 ctor 太多
- 为什么要删除基类的默认复制并移动ctor和赋值
- 如何在map中放置具有"deleted"复制ctor和赋值运算符的类?
- 如何使用运行时选择基 CTOR 初始化不可复制的基类