在类中的构造函数或运算符重载(例如:复制赋值运算符)声明的末尾键入 `= default` 的目的是什么?

Gab*_*les 3 c++ constructor default default-constructor

这个答案是什么是三的规则?有以下代码。请注意,除了第一个构造函数之外,所有构造函数= default;的末尾都有:

class person
{
    std::string name;
    int age;

public:
    person(const std::string& name, int age);        // Ctor
    person(const person &) = default;                // 1/5: Copy Ctor
    person(person &&) noexcept = default;            // 4/5: Move Ctor
    person& operator=(const person &) = default;     // 2/5: Copy Assignment
    person& operator=(person &&) noexcept = default; // 5/5: Move Assignment
    ~person() noexcept = default;                    // 3/5: Dtor
};
Run Code Online (Sandbox Code Playgroud)

虽然我以前见过很多次,但我不明白什么时候可以使用= default,或者为什么。在我看来,如果您想要defaultC++ 提供的构造函数或赋值运算符,您可以只删除该声明(以及任何相关的定义),不是吗?

明确禁止给定类型的任何其他构造函数的目的是什么?例如:也许这个

person& operator=(const person &) = default;     // 2/5: Copy Assignment
Run Code Online (Sandbox Code Playgroud)

坐在类定义的顶部只是让类的任何读者或用户都清楚地知道没有其他手动/显式复制赋值运算符存在或可以存在?

我可以在这里使用一些帮助来理解:

  1. 机制/它(即:= default在类中的构造函数或函数定义之后使用)的作用是什么?
    1. 它也适用于第一个构造函数吗?我在示例中的那个上没有看到它:(person(const std::string& name, int age);还有:这个构造函数有名字吗?“通用构造函数”也许?
  2. 何时使用
  3. 为什么要使用它

我对 C++ 更高级的特性还是很陌生。

更新

这是Scott Meyers 的一些额外见解:“对零规则的关注”(强调):(
如果这个问题没有结束,我可能会回答这个问题)。

另外的析构函数中有禁止代移动功能的副作用,但由于Widget是可复制,所有用来生成移动现在的代码将生成副本。换句话说,向类添加析构函数会导致可能高效的移动被静默地替换为可能效率较低的副本。这让我印象深刻,因为 (1) 可能会让人们感到惊讶,而 (2) 可能会使调试变得复杂。

我倾向于建议依赖编译器生成的复制和移动函数的更好方法是明确地说它们做正确的事情——通过=default以下方式定义它们:

 class Widget {
 public:
   Widget(const Widget&) = default;
   Widget(Widget&&) = default;

   Widget& operator=(const Widget&) = default;
   Widget& operator=(Widget&&) = default;

   ...
 };
Run Code Online (Sandbox Code Playgroud)

通过这种方法,零规则的精神仍然存在:不管理资源的类应该被设计成编译器生成的复制、移动和销毁函数做正确的事情。但不是通过不声明这些函数来表达这一点,而是通过明确声明它们来表达这一点,并且同样明确地选择加入编译器生成的实现。

你怎么认为?这个建议有意义吗?零规则是否应该是五个默认规则?

Scott 的博文到此结束。然后,在他帖子下方的评论中,他说:

我认为“全有或全无的规则”将是一个很好的规则。


回复被标记为重复/请求重新打开此问题:

我觉得这里标记为“已经有答案”的问题并未涵盖我所问问题的细微差别,我的问题应该重新打开,以允许其他人就我的问题的具体情况提供更多答案和见解。我看过它的答案。它的问题侧重于显式default调用泛型构造函数,但我的问题侧重于显式default调用一个或多个“5 法则”构造函数/赋值运算符,以及这如何影响其他构造函数的交互和响应。我现在投票重新打开我的问题。

沙盒:https : //godbolt.org/z/vWMsd3

也可以看看

  1. http://scottmeyers.blogspot.com/2014/03/a-concern-about-rule-of-zero.html
  2. 三分法则是什么?
  3. C++11 中的新语法“= default”
  4. 默认构造函数和析构函数的“=default”与“{}”有何不同?

bol*_*lov 6

看看 Howard Hinnant 的这张表,显示了何时隐式默认或未声明特殊方法:

在此处输入图片说明

是的 .. 正如你所看到的,规则非常复杂,如果你有一些特殊的成员用户声明,试图弄清楚自己是一个特殊的成员是隐式默认的还是未声明的根本不是一个选项。

因此,经验法则是,如果您至少声明其中之一,那么您应该声明default其余所有内容。