如果类包含用户声明的析构函数,那么复制构造函数会怎样?

What's with the copy-constructor if the class contains a user-declared destructor?

提问人: 提问时间:11/1/2014 最后编辑:Columbo 更新时间:3/18/2016 访问量:2943

问:

第 12.8/7 节中的标准说:

如果类定义未显式声明副本 构造函数,一个是隐式声明的。如果类定义 声明 Move 构造函数或 Move 赋值运算符, 隐式声明的复制构造函数定义为已删除;否则 它被定义为默认 (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()
{ 

}

演示

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

C++ 构造函数 language-lawyer 三法则

评论

5赞 T.C. 11/1/2014
三法则。如果它有一个用户定义的复制赋值运算符或析构函数,默认的复制构造函数可能不会做正确的事情,但实际上将其定义为删除将是一个巨大的重大更改,并对大量现有代码造成严重破坏;因此,它仅被弃用。如果你有一个移动特殊成员,那么它必须是新代码,所以删除它不会破坏任何东西。
0赞 11/1/2014
@T.C. 基本上弃用意味着使用该特定功能不好,但如果您渴望,您可以这样做,不是吗?
1赞 Titus 11/1/2014
+1 让我从标准中学到一些东西

答:

5赞 Columbo 11/1/2014 #1

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

在此示例中,标准既不提供副本分配,也不提供副本分配 析构函数是用户标记的。

该示例与弃用无关。

我尝试这样做如下:[...]但是在示例中,我们仍然有隐式声明的副本 构造 函数。

您不能定义隐式声明的复制构造函数 - 因为它已经定义了(没有双关语)。您必须先自己声明。= default

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

引用了显式指定在声明移动构造函数时将复制构造函数隐式定义为删除的规则:

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

清楚

A(const A&&){ }

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

评论

0赞 11/1/2014
但标准中的例子格式不正确:coliru.stacked-crooked.com/a/f88c8ce871b6be9a
0赞 11/1/2014
这意味着如果我们使用 copy-constructor 会发生什么,就没有意义了......我认为
0赞 Mike Seymour 11/1/2014
@DmitryFucintv:是的,这个例子的格式不正确,就像标准后面所说的那样。这句话的其余部分,在你发布的片段之后,是“那么,由于歧义,任何对 X 的复制构造函数的使用都是格式错误的;不需要诊断。
0赞 11/2/2014
@MikeSeymour 我认为如果我们在表达式中使用构造函数,程序的格式会不正确。“那么由于歧义,任何对 X 的复制构造函数的使用都是格式错误的;不需要诊断。也就是说,如果我们只声明一个,程序就不会格式错误。怎么了?
0赞 11/2/2014
@MikeSeymour顺便说一句,正如 T.C. 所指出的那样,该 open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1344 存在一个问题
1赞 Scooter 11/1/2014 #2

弃用通常意味着某些东西可以工作,但它不受欢迎,将来可能不起作用。我认为标准是说,如果您创建用户声明的复制分配运算符或用户声明的析构函数,它仍将创建默认的复制构造函数(如果您还没有) - 但将来可能不会。因此,他们希望你现在创建自己的复制构造函数,如果你有另外两个中的一个,将来他们可能会强迫你这样做。