默认定义声明的详细程度不完整

Incomplete verbosity of default definitions declarations

本文关键字:程度不 定义 声明 默认      更新时间:2023-10-16

在Stroustrup的C++之旅中,他提到:

如果明确某些默认值,则不会生成其他默认定义。

但是,gcc 4.9.1 似乎并非如此。举个例子:

#include <iostream>
using namespace std;
struct A 
{
    int data;
    A() = default;
    A(const A&) = default;
};
int main() 
{
  A a;
  a.data = 10;
  A b(a);
  A c;
  c = a;
  cout<<b.data<<endl;
  cout<<c.data<<endl;
  return 0;
}

它编译并给出预期的输出,即已经生成了默认赋值运算符。

我误解了斯特劳斯特鲁普的评论吗?

首先,你的代码不使用类的赋值运算符,所以它不证明它的存在。但是,添加它的用途

c = a;

会起作用,所以问题仍然存在。

声明任何特殊函数并不能阻止生成所有其他特殊函数,这似乎是您解释报价的方式。声明一些会抑制其他一些。没有读过这本书来把这句话放在上下文中,我不能说它是否具有误导性。

规则大致如下:

  • 声明任何构造函数将阻止隐式默认构造函数;
  • 声明移动构造函数或移动赋值运算符
  • 将阻止隐式复制构造函数和复制赋值运算符;
  • 声明析构函数、复制构造函数或复制赋值运算符将阻止隐式移动构造函数和移动赋值运算符;

这是一种简化;还有更多的细微差别和例外。如果您想要血腥的细节,请阅读语言规范。

这些

声明当前是默认生成的(这就是您提供的代码起作用的原因(,但此行为在对C++标准的进一步修订(已弃用(中随时可能被删除。

在Stroustrup的C++11常见问题解答中,他说

如果用户显式指定了任何移动、复制或析构函数(声明、定义、=default 或 =delete(,则默认情况下不会生成任何移动。

这是不言自明的。然而,他接着说...

如果用户显式指定了任何移动、复制或析构函数(声明、定义、=default 或 =delete(,则默认情况下会生成任何未声明的复制操作,但这已弃用,因此不要依赖它。

然后他列举了几个例子:

class X1 {
    X1& operator=(const X1&) = delete;  // Disallow copying
};

这也隐式地禁止移动 X1。 允许复制初始化,但已弃用。

class X2 {
    X2& operator=(const X2&) = delete;
};

这也隐含地禁止移动 X2s。 允许复制初始化,但已弃用。

class X3 {
    X3& operator=(X3&&) = delete;   // Disallow moving
};

这也隐含地禁止复制 X3。

class X4 {
    ~X4() = delete; // Disallow destruction
};

这也隐含地禁止移动 X4。 允许复制,但已弃用。