C 11 三规则变成五规则?

新手上路,请多包涵

所以,在看了 这个关于右值引用的精彩讲座 之后,我认为每个班级都会受益于这样的“移动构造函数”, template<class T> MyClass(T&& other) 编辑,当然还有“移动赋值运算符”, template<class T> MyClass& operator=(T&& other) 正如菲利普在他的回答中指出的那样,如果它具有动态分配的成员,或者通常存储指针。就像如果前面提到的要点适用,你 应该 有一个复制ctor、赋值运算符和析构函数。想法?

原文由 Xeo 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 674
2 个回答

我会说三法则变成三、四、五法则:

每个类都应明确定义以下一组特殊成员函数之一:

  • 没有任何
  • 析构函数、复制构造函数、复制赋值运算符

此外,显式定义析构函数的每个类都可以显式定义移动构造函数和/或移动赋值运算符。

通常,以下一组特殊成员函数是合理的:

  • 无(对于隐式生成的特殊成员函数正确且快速的许多简单类)
  • 析构函数、复制构造函数、复制赋值运算符(在这种情况下,类将不可移动)
  • 析构函数、移动构造函数、移动赋值运算符(在这种情况下,类将不可复制,对于底层资源不可复制的资源管理类很有用)
  • 析构函数、复制构造函数、复制赋值运算符、移动构造函数(由于复制省略,如果复制赋值运算符按值获取其参数,则没有开销)
  • 析构函数、复制构造函数、复制赋值运算符、移动构造函数、移动赋值运算符

笔记:

  • 对于显式声明任何其他特殊成员函数(如析构函数或复制构造函数或移动赋值运算符)的类,不会生成移动构造函数和移动赋值运算符。
  • 不会为显式声明移动构造函数或移动赋值运算符的类生成复制构造函数和复制赋值运算符。
  • 并且具有显式声明的析构函数和隐式定义的复制构造函数或隐式定义的复制赋值运算符的类被视为已弃用。

特别是,以下完全有效的 C++03 多态基类:

 class C {
  virtual ~C() { }   // allow subtype polymorphism
};

应改写如下:

 class C {
  C(const C&) = default;               // Copy constructor
  C(C&&) = default;                    // Move constructor
  C& operator=(const C&) = default;  // Copy assignment operator
  C& operator=(C&&) = default;       // Move assignment operator
  virtual ~C() { }                     // Destructor
};

有点烦人,但可能比替代方案更好(在这种情况下,自动生成 用于复制的特殊成员函数,没有移动的可能性)。

与不遵守规则会导致严重损害的三巨头规则相反,不明确声明移动构造函数和移动赋值运算符通常很好,但在效率方面往往不是最优的。如上所述,移动构造函数和移动赋值运算符只有在没有显式声明的复制构造函数、复制赋值运算符或析构函数时才会生成。这在复制构造函数和复制赋值运算符的自动生成方面与传统的 C++03 行为不对称,但更安全。因此,定义移动构造函数和移动赋值运算符的可能性非常有用,并创造了新的可能性(纯粹的可移动类),但遵守 C++03 三巨头规则的类仍然可以。

对于资源管理类,如果无法复制基础资源,您可以将复制构造函数和复制赋值运算符定义为已删除(视为定义)。通常您仍然需要移动构造函数和移动赋值运算符。复制和移动赋值运算符通常使用 swap 来实现,如在 C++03 中。谈论 swap ;如果我们已经有一个移动构造函数和移动赋值运算符, 专门的 std::swap 将变得 _不重要_,因为通用 std::swap 使用移动构造函数和移动赋值运算符(如果可用)(和那应该足够快)。

不用于资源管理(即没有非空析构函数)或子类型多态性(即没有虚拟析构函数)的类不应声明五个特殊成员函数中的任何一个;它们都将自动生成,并且行为正确且快速。

原文由 Philipp 发布,翻译遵循 CC BY-SA 4.0 许可协议

以下是自 2011 年 1 月 24 日以来有关当前状态和相关发展的简短更新。

根据 C++11 标准(见附件 D 的 [depr.impldec]):

如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用复制构造函数的隐式声明。如果类具有用户声明的复制构造函数或用户声明的析构函数,则不推荐使用复制赋值运算符的隐式声明。

实际上,有人 提议 废除已弃用的行为 ,为 C++14 提供真正的“五规则”,而不是传统的“三规则”。 2013 年,EWG 投票反对在 C++2014 中实施的提案。对该提案做出决定的主要理由与对破坏现有代码的普遍担忧有关。

最近,再次 提出 修改 C++11 的措辞,以实现非正式的五规则,即

如果这些函数中的任何一个是用户提供的,则编译器不会生成任何复制函数、移动函数或析构函数。

如果得到 EWG 的批准,“规则”很可能会被 C++17 采用。

原文由 Andrey Rekalo 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题