编译器自动生成的操作
C++编译器会自动生成一些默认操作
- 默认构造函数
- 析构函数
- 拷贝构造函数
- 复制运算符
- 移动构造函数
- 移动赋值运算符
这些操作别分为两组:默认构造函数自己为一组,其他5个为一组
- 如果程序员定义了任意构造函数,编译器就不再生成默认构造函数
- 后面5个操作为一组,称为拷贝控制成员,用于处理类对象的复制、赋值和销毁。
- 如果程序员定义了5个成员中的任意一个,编译器就不会自动生成其他的成员
为什么要这样分组
这里分几种情况讨论
- 简单的数据类
此时类的功能和C语言的结构体类似,类本身没有功能,甚至不会定义构造函数。这种情况下,C++编译器会自动生成默认构造函数,数据成员的值执行默认初始化
虽然默认初始化的结果不一定就是程序员想要的,但是一般也不会有什么问题
- 没有资源管理的类
和简单的数据类相比,这种类比简单数据类增加了相应的内部逻辑,因此数据之间也会有一些内在的联系。这时默认初始化往往就不能满足要求了,解决的方法就是定义构造函数
作为C++编译器,一旦程序员定义了构造函数,就可以认为默认初始化已经不能满足需求从而不会再生成默认的构造函数了。这种处理方式再大多数的情况下会更加安全
C++以后,如果程序员还是希望编译器生成默认构造函数,可以通过=default
实现
由于不存在资源管理的需求,这个类还不是必须定义析构函数
- 包含资源管理的功能类
一旦类中包含了需要释放的资源,比如端口、内存、文件等,就需要定义一个析构函数来释放这些资源。析构函数在对象销毁的时候被自动调用,正好可以完成这个任务。
一般来讲,一旦在析构函数中需要释放资源,在其他的拷贝控制成员也需要进行相应的处理
和自动生成的默认构造函数的规则类似,如果定义了某个拷贝控制成员,编译器就不再自动生成其他的。(这条规则不是完整实施的:出于向后兼容的需求,即使程序员定义了析构函数,编译器还是会自动生成拷贝构造函数和拷贝赋值运算符。但是这一特征在ISO标准中已经启用了,你可以期望一个现代编译器能对此给出警告。)
当然也存在像浅拷贝那样,编译器自动生成的拷贝控制成员就可以满足需求的情况,这时可以对拷贝控制成员使用=default
要求编译器生成某些拷贝控制成员