如果我们未定义拷贝控制成员,编译器会为我们合成;如一个类未定义构造函数,编译器会为我们合成一个默认的构造函数。

合成拷贝控制成员可能是删除的情况:

  1. 如果类中有成员的析构函数是删除的或不可访问的(private):
    a. 则类的合成析构函数被定义为删除的;
    b. 则合成拷贝构造函数被定义为删除的;
    c. 若类内有引用成员没有类内初始化器,或类内有一个const成员没有类内初始化器,
    且其类型未显式的定义默认构造函数,则该类的默认构造函数被定义为删除的。
  2. 如果类中有成员的拷贝函数是删除的或不可访问的(private):
    a. 则类的合成拷贝函数被定义为删除的;
  3. 如果类中有成员函数的赋值运算符是删除的或不可访问的(private),
    或类有一const的或引用成员:
    a. 则类的合成拷贝赋值运算符被定义为删除的。

移动操作

与拷贝操作不同,移动操作永远不会隐式定义为删除的函数。但是,如果我们显式地要求编译器生成=default 的 (参见 7.1.4节,第 237 页)移动操作,且编译器不能移动所有成员,则编译器会将移动操作定义为删除的函数。
除了一个重要例外,什么时候将合成的移动操作定义为删除的函数遵循与定义删除的合成拷贝操作类似的原则(参见 13.1.6节,第 449 页):

  • 与拷贝构造函数不同,移动构造函数被定义为删除的函数的条件是:有类成员定义了自己的拷贝构造函数且未定义移动构造函数,或者是有类成员未定义自己的拷贝构造函数且编译器不能为其合成移动构造函数。移动赋值运算符的情况类似。
  • 如果有类成员的移动构造函数或移动赋值运算符被定义为删除的或是不可访问的,则类的移动构造函数或移动赋值运算符被定义为删除的。
  • 类似拷贝构造函数,如果类的析构函数被定义为删除的或不可访问的,则类的移动构造函数被定义为删除的。
  • 类似拷贝赋值运算符,如果有类成员是const的或是引用,则类的移动赋值运算符被定义为删除的。

只有当一个类没有定义任何自己版本的拷贝控制成员,且类的每个非 static 数据成员都可以移动时,编译器才会为它合成移动构造函数或移动赋值运算符。编译器可以移动内置类型的成员。
如果一个成员是类类型,且该类有对应的移动操作,编译器也能移动这个成员。// 如果定义了拷贝构造函数,就不会再生成默认的移动拷贝了。

移动操作和合成的拷贝控制成员间还有最后一个相互作用关系:一个类是否定义了自己的移动操作对拷贝操作如何合成有影响。如果类定义了一个移动构造函数和/或一个移动赋值运算符,则该类的合成拷贝构造函数和拷贝赋值运算符会被定义为删除的。

定义了一个移动构造函数或移动赋值运算符的类必须也定义自己的拷贝操作否则,这些成员默认地被定义为删除的。



摘自《C++ Primer》