17 理解特殊成员函数的生成
17 理解特殊成员函数的生成
移动构造和拷贝构造是编译器默认生成的内容,虽然移动构造在某些成员身上表现为拷贝构造。
生成规则
拷贝构造
两个拷贝构造之间是相互独立的:声明一个不会限制编译器生成另一个。所以如果你声明一个拷贝构造函数,但是没有声明拷贝赋值运算符,如果写的代码用到了拷贝赋值,编译器会帮助你生成拷贝赋值运算符。
移动构造
两个移动操作不是相互独立的。如果你声明了其中一个,编译器就不再生成另一个。
关联互斥
如果一个类显式声明了拷贝操作,编译器就不会生成移动操作。
声明移动操作(构造或赋值)也使得编译器禁用拷贝操作。
Rule_Of_Three规则
这个规则告诉我们:如果你声明了拷贝构造函数,拷贝赋值运算符,或者析构函数三者之一,你应该也声明其余两个。
由此出现了推理:当出现了析构函数,会影响移动构造函数的默认生成。(但不影响拷贝操作)
由于Rule_Of_Three
规则以及 拷贝与移动之间的默认互斥,所以仅当下面条件成立时才会自动生成移动操作(当需要时):
-
类中没有拷贝操作
-
类中没有移动操作
-
类中没有用户定义的析构
尽可能使用default代替隐式生成
由于Rule_Of_Three规则,因此尽可能为特殊成员函数使用default代替隐式生成。因为开始时开发的默认隐式生成的共识,可能会被后续开发添加的析构函数而打破。
特殊成员函数的生成规则
-
默认构造函数:和C++98规则相同。仅当类不存在用户声明的构造函数时才自动生成。
-
析构函数:基本上和C98相同;稍微不同的是现在析构默认
noexcept
(参见Item14)。和C98一样,仅当基类析构为虚函数时该类析构才为虚函数。 -
拷贝构造函数:和C++98运行时行为一样:逐成员拷贝non-static数据。仅当类没有用户定义的拷贝构造时才生成。如果类声明了移动操作它就是delete的。当用户声明了拷贝赋值或者析构,该函数自动生成已被废弃。
-
拷贝赋值运算符:和C++98运行时行为一样:逐成员拷贝赋值non-static数据。仅当类没有用户定义的拷贝赋值时才生成。如果类声明了移动操作它就是delete的。当用户声明了拷贝构造或者析构,该函数自动生成已被废弃。
-
移动构造函数和移动赋值运算符:都对非static数据执行逐成员移动。仅当类没有用户定义的拷贝操作,移动操作或析构时才自动生成。
边缘规则:函数模板不会阻止编译器生成特殊成员函数
由于标准中没有这种规则:函数模板阻止编译器生成特殊成员函数。因此,下面的代码,编译器仍然会生成移动和拷贝构造,即使模板会产出拷贝构造和拷贝运算符的函数签名:
class Widget { |