编译器何时为类的特殊成员提供定义?

Posted

技术标签:

【中文标题】编译器何时为类的特殊成员提供定义?【英文标题】:When does the compiler provide definitions for the special members of a class? 【发布时间】:2012-01-27 02:36:13 【问题描述】:

我知道,当我定义一个空类并且根本不提供任何声明时,编译器会为默认和复制构造函数、析构函数和复制赋值运算符提供定义。

这有什么规则?编译器何时提供复制构造函数?移动构造函数和移动赋值运算符呢?

(例如:如果我的类有 int& 这样的引用成员,编译器将不会为任何赋值运算符提供定义。其他什么时候会发生这种情况?)

【问题讨论】:

@Mr.TAMER:***很好,但我想有一个完整的 SO 列表,最好是标准引号。 :) 此外,***文章没有说明何时获得移动构造函数以及何时不提供复制 ctor / 赋值操作。 会不会不提供赋值运算符,即使你有引用成员。尝试使用它会生成编译,不是因为它不存在,而是因为它无效。 在不输入标准第 12 章的大量内容的情况下,我们应该如何回答这个问题?这一切都在那里,它是标准中非常明确的一部分。 “我知道,当我定义一个空类并且根本不提供任何声明时,编译器将提供默认和复制构造函数、析构函数和复制赋值运算符的定义。”。这是不正确的。它只会提供这些的声明。并且定义仅在需要时使用。 @Xeo 不,这些不是形式。如果你有struct A void operator=(int); operator int(); int &x; ; A a*new int, b*new int;,如果你说a = b;,它会给出一个错误,因为它确实提供了复制分配的声明。如果不是,它不是是一个错误,但它会将b转换为int 【参考方案1】:

编辑:在 C++11 中,它比隐式声明或不隐式声明更复杂。它们可以被隐式声明和默认,隐式声明和删除,或未声明。阅读this以区分后者2。以下信息并不完全正确,因为它不区分已声明和已删除与未声明。

以下是正在进行的工作。 (?) 表示我想澄清或量化该声明。

特殊成员函数 §12/1

当用户没有显式声明它们时,实现会为某些类类型隐式声明这些成员函数:

默认构造函数 复制构造函数 复制赋值运算符 移动构造函数 移动赋值运算符 析构函数

如果类型有一个特殊的成员函数,则不会隐式声明...


默认构造函数§12.1/5


复制构造函数§12.8/8, §12.8/12

用户声明的移动构造函数 用户声明的移动赋值运算符 右值引用类型的非静态数据成员 具有非平凡复制构造函数的变体成员并且是类联合类 (?) 无法复制的类型(或其数组)的非静态数据成员 没有可访问复制构造函数的直接或虚拟基类

*如果类具有用户声明的复制赋值运算符或用户声明的析构函数 (?),则不推荐使用此类隐式声明


复制赋值运算符§12.8/19, §12.8/24

用户声明的移动构造函数 用户声明的移动赋值运算符 具有非平凡复制赋值运算符的变体成员,是类联合类 (?) const 非类类型(或其数组)的非静态数据成员 引用类型的非静态数据成员 具有不可访问的复制赋值运算符的非静态数据成员 具有不可访问的复制赋值运算符的直接或虚拟基类

*如果类具有用户声明的复制构造函数或用户声明的析构函数 (?),则不推荐使用此类隐式声明


移动构造函数§12.8/10, §12.8/12

用户声明的复制构造函数 用户声明的复制赋值运算符 用户声明的移动赋值运算符 用户声明的析构函数 移动构造函数不会被隐式定义为已删除 (?) variant 成员具有非平凡的移动构造函数并且是类联合类 (?) 不能移动的类型(或其数组)的非静态数据成员 非静态数据成员或直接或虚拟基类,其类型没有移动构造函数且不可轻易复制 没有可访问的移动构造函数的直接或虚拟基类

移动赋值运算符§12.8/21, §12.8/24

用户声明的复制构造函数 用户声明的移动构造函数 用户声明的复制赋值运算符 用户声明的析构函数 移动赋值运算符不会被隐式定义为已删除 (?) 具有非平凡移动赋值运算符的变体成员,是类联合类 (?) const 非类类型(或其数组)的非静态数据成员 引用类型的非静态数据成员 具有不可访问的移动赋值运算符且不可轻易复制的非静态数据成员 具有不可访问的移动赋值运算符且不可轻易复制的直接或虚拟基类

析构函数§12.4/4

【讨论】:

以上是关于编译器何时为类的特殊成员提供定义?的主要内容,如果未能解决你的问题,请参考以下文章

构造方法

JavaSE阶段初期的一些问题

将声明的枚举转发为类成员变量

何时子类必须显示调用父类带参构造函数

何时使用 alloca 为类成员分配内存?

C++:= default & = delete