6

第 12.8/7 节中的标准说:

如果类定义没有显式声明复制构造函数,则隐式声明。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数定义为已删除;否则,它被定义为默认值(8.4)。如果 类具有用户声明的复制赋值运算符或用户声明的 析构函数,则不推荐使用后一种情况。因此,对于类定义

struct X {
    X(const X&, int);
};

复制构造函数是隐式声明的。如果用户声明的构造函数后来被定义为

X::X(const X& x, int i =0) { /∗ ... ∗/ }

我不明白如果该类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况。在示例中,标准既不提供用户声明的复制赋值运算符也不提供析构函数。如果我们声明析构函数或复制赋值运算符会发生什么?我试图这样做如下:

struct A
{
    ~A(){ };
};

A::A(const A&){ }; //error

int main(){ }

演示

但在示例中,我们仍然有隐式声明的复制构造函数。该规则的实际含义是什么?

我想如果我们写以下内容:

struct A
{
    A(){ };
    A(const A&&){ };
    ~A(){ };
};

A a;

A t = a; //error: call to implicitly-deleted copy constructor of 'A'

int main()
{ 

}

演示

复制构造函数不会显式删除。但事实并非如此。

4

2 回答 2

5

这种弃用基本上包含了三(五)规则。如果提供了用户声明的复制赋值运算符或析构函数,则不推荐将复制构造函数定义为默认(而不是删除)的事实。这应该可以防止您将来依赖这种隐式声明的复制构造函数。

在示例中,标准既不提供复制分配也不提供析构函数是用户自定义的。

该示例与弃用无关。

我已经尝试按如下方式执行此操作:[…] 但在示例中,我们仍然有隐式声明的复制构造函数。

你不能定义一个隐式声明的复制构造函数——因为它已经被定义了= default(不是双关语)。您必须先自己声明。

我认为如果我们写以下内容:[…] 复制构造函数不会显式删除。但事实并非如此。

引用的规则明确指定如果声明了移动构造函数,则复制构造函数将被隐式定义为已删除:

如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数定义为已删除;

清楚地,

A(const A&&){ }

是根据 [class.copy]/3 的移动构造函数。如果您删除了此移动构造函数,那么您的示例将编译,尽管它使用了所述已弃用的功能。

于 2014-11-01T08:39:43.030 回答
1

不推荐使用通常意味着某些东西会起作用,但它被不赞成并且将来可能不起作用。我认为标准是说,如果您创建用户声明的复制赋值运算符或用户声明的析构函数,它仍将创建一个默认的复制构造函数(如果您没有) - 但将来可能不会。所以他们希望你现在创建自己的复制构造函数,如果你有另外两个之一,将来他们可能会强迫你这样做。

于 2014-11-01T08:50:16.593 回答