自动生成默认/复制/移动控制器和复制/移动分配运算符的条件?


Answers:


136

在下文中,“自动生成”是指“隐式声明为默认值,但未定义为已删除”。在某些情况下,会声明特殊成员函数,但将其定义为已删除。

  • 如果没有用户声明的构造函数,则将自动生成默认的构造函数(第12.1 / 5节)。
  • 如果没有用户声明的move构造函数或move赋值运算符,则复制构造函数会自动生成(因为在C ++ 03中没有move构造函数或move赋值运算符,因此在C ++ 03中简化为“始终”)( §12.8/ 8)。
  • 如果没有用户声明的移动构造函数或移动分配运算符(第12.8 / 19节),则会自动生成副本分配运算符。
  • 如果没有用户声明的析构函数,则析构函数将自动生成(第12.4 / 4节)。

仅C ++ 11和更高版本:

  • 如果没有用户声明的副本构造函数,副本分配运算符或析构函数,并且所生成的Move构造函数有效(第12.8 / 10节),则将自动生成move构造函数。
  • 如果没有用户声明的副本构造函数,副本分配运算符或析构函数,并且所生成的移动赋值运算符有效(例如,如果不需要分配常量成员),则将自动生成该移动赋值运算符(第12.8节/ 21)。

9
继承的析构函数是否计数?我的意思是说我有一个带有空虚析构函数的基类。是否阻止在子类中创建move构造函数?如果答案是肯定的,那么在基类中定义move构造函数会有所帮助吗?
卡米尔克,2014年

10
我认为您应该提到也许const在类中拥有成员会阻止构造函数自动生成...
不知情的2014年

是否“在某些情况下已声明特殊成员函数,但将其定义为已删除”。指的是您有const或引用成员的位置,例如,将无法进行移动?不,那不可能,因为将应用副本。
towi

我知道在此论坛中发送超链接是受限制的。但这也是很好的文章-cplusplus.com/articles/y8hv0pDG
bruziuz

注意,从标准上讲,如果类具有用户声明的副本分配运算符或用户声明的析构函数,则不建议使用隐式默认的副本构造函数 “(12.8复制和移动类对象[class.copy])。
sigy

98

我发现下面的图非常有用。

自动构造函数和赋值运算符的C ++规则Sticky Bits-成为零英雄规则


美丽。“独立”指的是什么?独立于什么?
towi

8
复制ctor /分配彼此“独立”。如果仅编写一个,则编译器将提供另一个。相反,如果您提供了一个移动ctor或一个移动分配,则编译器将不提供另一个。
Marco M.

不知道复制操作为何独立是什么原因。历史原因可能是?还是复制不会修改其目标却移动的事实呢?
RaGa__M

@Explorer_N是的,向后兼容,是历史原因。很久以前,这是一个错误的设计选择,因此现在需要一些良好的实践,例如“三个规则”(定义所有3个或不定义:复制构造函数,复制赋值运算符和通常为析构函数),以避免难以发现错误。
atablash

@MarcoM。据我所知,“如果您写...”条件包括将特殊成员函数设置为= delete(显而易见)或= default(对我而言不太明显)的两种情况。我对吗?
恩里科·玛丽亚·德·安吉利斯

2

C ++ 17 N4659标准草案

有关快速交叉标准的参考,请查看以下cppreference条目的“隐式声明”部分:

当然可以从标准中获得相同的信息。例如在C ++ 17 N4659标准草案中

15.8.1“复制/移动构造函数”对于复制构造函数说:

6如果类定义未显式声明一个副本构造函数,则隐式声明一个非显式的构造函数。如果类定义声明了move构造函数或move赋值运算符,则隐式声明的copy构造函数将定义为Delete;否则,将其定义为默认值(11.4)。如果该类具有用户声明的副本分配运算符或用户声明的析构函数,则不建议使用后者。

对于移动构造函数:

8如果类X的定义未明确声明移动构造函数,则仅当且仅当非显式类的隐式声明为默认值

  • (8.1)— X没有用户声明的副本构造函数,

  • (8.2)— X没有用户声明的副本分配运算符,

  • (8.3)— X没有用户声明的移动分配运算符,并且

  • (8.4)— X没有用户声明的析构函数。

15.8.2“复制/移动分配操作员”说:

2如果类定义未显式声明一个副本分配运算符,则隐式声明一个。如果类定义声明了move构造函数或move赋值运算符,则隐式声明的副本赋值运算符将定义为Delete;否则,将其定义为默认值(11.4)。如果该类具有用户声明的副本构造函数或用户声明的析构函数,则不建议使用后一种情况。

对于移动分配:

4如果类X的定义未明确声明移动分配运算符,则仅当且仅当将隐式声明为默认值

  • (4.1)— X没有用户声明的副本构造函数,
  • (4.2)— X没有用户声明的move构造函数,
  • (4.3)— X没有用户声明的副本分配运算符,并且
  • (4.4)— X没有用户声明的析构函数。

15.4“析构函数”对析构函数说:

4如果类没有用户声明的析构函数,则将析构函数隐式声明为默认值(11.4)。隐式声明的析构函数是其类的内联公共成员。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.