在C++98中,有四种特殊成员函数,分别为:
1默认构造函数
2默认析构函数
3默认拷贝构造函数
4默认拷贝赋值函数
上面这4个特殊成员函数有如下特点:
1只在你没有在类的定义中显式声明他们的时候,C++才会去创建他们。
2他们默认是inline类型的
3他们是non-virtual的,除非这个成员函数是析构函数,并且这个类的父类的析构函数是virtual的,这时候,c++会为这个子类产生一个virtual类型的析构函数。
在C++11中,新增了两个特殊成员函数:移动构造函数和移动赋值运算符:
class Widget {
public:
Widget(Widget&& rhs); // move constructor
Widget& operator=(Widget&& rhs); //move assignment operator
};
Move操作是类成员级别的move,也就是说move是将类中的成员逐个地move,由于并不是类中的所有成员都支持move操作,所以,move是部分move。
如果类成员不支持move操作(如某个对象成员没有定义move构造函数,C++98标准下的类就没有move函数,所以也就不支持move操作),这时,会调用这些类的拷贝构造函数。如果是普通的成员变量,则会直接复制这个成员变量。
注意:
1这两个move函数是相互关联的,只有当你没有显式声明他们当中任何一个时,c++才会自动生成这些函数,如果你声明了其中任何一个move函数,那么这两个move函数都不会由c++自动生成了。
2 当你显式声明了拷贝构造函数或者拷贝赋值函数中的任何一个时,C++都不会再生成move函数了,当我们显式声明了一个拷贝函数时,这就表明通常的拷贝对象方式(逐个数据成员的拷贝)已经不适合这个类了,move操作是“数据成员”级的move,编译器认为如果“成员级”的拷贝不适合这个类的拷贝操作,那么“成员级”的move也不适合这个类。
3反过来说,当你声明了两个move函数中的任何一个,那么编译器也就不会再为这个类生成拷贝函数了。
4如果一个类中有显式声明的析构函数,C++将不会再为其产生move函数。
Rule of Three: 当你声明了“拷贝构造函数”,“拷贝赋值函数”,“析构函数”中的任意一个时,你也应当声明另外的两个。原因:一个类需要显式自定义的拷贝构造函数,多是因为它要管理资源,那么,拷贝赋值函数以及析构函数自然也就被牵扯到资源管理中来了。
总结:只有下面三个条件都满足时,move函数才会被C++自动生成:
1没有显式声明copy函数(拷贝构造和拷贝赋值)
2没有声明任何move函数(move构造函数和move赋值函数)
3没有显式声明析构函数
C++11 对于特殊函数的生成规则
1 默认构造函数:规则与C++98相同,只有当类中没有显式声明构造函数时,C++才会自动为其生成一个无参的默认构造函数。
2析构函数:与C++98相同,只有当基类的析构函数是virtual时,子类的析构函数才会是virtual的。
3拷贝构造函数:运行时行为与C++98相同,成员级拷贝,即逐个会拷贝类的non-static数据成员。只有当类中没有显式声明拷贝构造函数和move函数时,C++才会自动生成。为一个有显式拷贝赋值函数或者析构函数的类自动生成拷贝构造是被阻止的。
4拷贝赋值运算符:运行时行为与C++98相同,成员级拷贝,只有当类中没有显式声明的拷贝构造函数或者任何move函数时,才会自动生成。为一个具有显式拷贝构造函数或者析构函数的类自动生成拷贝赋值函数是被阻止的。
5move构造函数和move赋值运算符:成员级move,即它会逐个move类中的non-static数据成员。只有类中不包含显式的拷贝函数,move函数,析构函数时才会产生。
6模板成员函数的存在并不会阻止C++产生特殊成员函数,比如,在如下代码中:
class Widget {
template<typename T> //copy-construct Widget
Widget(const T& rhs); //from anything
template<typename T> //copy-assign Widget
Widget& operator=(const T& rhs); //from anything
};
编译器仍然会自动生成拷贝函数和move函数,即使当T为Widget时,模板会实例化为拷贝函数。