提问人: 提问时间:11/1/2014 最后编辑:Columbo 更新时间:3/18/2016 访问量:2943
如果类包含用户声明的析构函数,那么复制构造函数会怎样?
What's with the copy-constructor if the class contains a user-declared destructor?
问:
第 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()
{
}
复制构造函数不会显式删除。但事实并非如此。
答:
这种弃用基本上包含了三(五)法则。如果提供了用户声明的复制分配运算符或析构函数,则不推荐使用将复制构造函数定义为默认值(而不是删除)的事实。这应该可以防止您将来依赖这种隐式声明的复制构造函数。
在此示例中,标准既不提供副本分配,也不提供副本分配 析构函数是用户标记的。
该示例与弃用无关。
我尝试这样做如下:[...]但是在示例中,我们仍然有隐式声明的副本 构造 函数。
您不能定义隐式声明的复制构造函数 - 因为它已经定义了(没有双关语)。您必须先自己声明。= default
我以为如果我们使用以下内容:[...] 复制构造函数不会显式删除。但事实并非如此。
您引用了显式指定在声明移动构造函数时将复制构造函数隐式定义为删除的规则:
如果类定义声明 move 构造函数或 move 赋值运算符,隐式声明的复制构造函数是 定义为已删除;
清楚
A(const A&&){ }
是根据 [class.copy]/3 的移动构造函数。如果删除了此移动构造函数,则示例将进行编译,尽管它使用了上述已弃用的功能。
评论
弃用通常意味着某些东西可以工作,但它不受欢迎,将来可能不起作用。我认为标准是说,如果您创建用户声明的复制分配运算符或用户声明的析构函数,它仍将创建默认的复制构造函数(如果您还没有) - 但将来可能不会。因此,他们希望你现在创建自己的复制构造函数,如果你有另外两个中的一个,将来他们可能会强迫你这样做。
上一个:三法则的例外?
评论