自动生成移动操作的规则是什么?

在C ++ 98中,C ++编译器可以自动生成拷贝构造函数和拷贝赋值操作符,例如通过成员拷贝

struct X { std::string s; std::vector<int> v; int n; }; 

编译器自动生成X拷贝构造函数和拷贝赋值操作符,使用成员级拷贝。

但是,在移动语义的情况下,C ++ 11中的事情是如何改变的?

移动 构造函数移动 赋值运算符是否 自动生成,如复制构造函数和复制赋值运算符?

有没有移动操作不会自动生成的情况?

从标准Ch。 12 – 特殊成员职能

参12.8 复制和移动类对象 (强调我的)

9。 如果类X的定义没有明确声明一个移动构造函数, 那么当且仅当

– X没有用户声明的拷贝构造函数,

– X没有用户声明的复制赋值操作符,

– X没有用户声明的移动赋值运算符,并且

X没有用户声明的析构函数。

[注意:当移动构造函数没有被隐式声明或显式提供时,否则将调用移动构造函数的expression式可能会调用复制构造函数。 – 注意]

然后, 11解释了删除默认移动构造函数的规则

11。 隐式声明的复制/移动构造函数是其类的内联公共成员。 X的缺省拷贝/移动构造函数被定义为删除(8.4.3),如果X有:

– 一个不平凡的对应构造函数的变体成员,X是一个类似于联合体的类,

– types为M(或其数组)的非静态数据成员不能复制/移动,因为应用于M的相应构造函数的重载parsing(13.3)会导致模糊或函数被删除或无法从默认的构造函数,

– 直接的或虚拟的基类B不能复制/移动,因为应用于B的相应构造函数的重载parsing(13.3)会导致从默认的构造函数中删除或无法访问的歧义或函数,

– 任何直接或虚拟的基类或非静态数据成员,其types的析构函数从默认的构造函数中被删除或不可访问,

– 对于拷贝构造函数,是右值引用types的非静态数据成员。 定义为删除的默认移动构造函数被重载parsing(13.3,13.4)忽略。

[注意:删除的移动构造函数会影响可以使用复制构造函数的右值的初始化。 – 注意]


关于它的复杂性,所有*

规则可以有点压倒一切。 使用一些技术来绕过复杂性是很好 。 例子是:

  1. 利用零规则来简化大部分类的写作。
  2. (关于隐式删除)显式地默认有问题的特殊成员函数; 如果它被隐含地定义为删除,编译器将会抱怨。

*我自己评论(1)和dyp (2)

尼科斯Athanasiou给了一个很好的答案,但我想添加这个工具,我认为是非常有用的。

下面是来自ACCU 2014会议的Howard Hinnant的演讲“你想知道关于移动语义的一切(然后是一些)”的截图,我认为这是对特殊成员自动生成规则的一个很好的提醒:

在这里输入图像描述

Hinnant先生从评论中澄清:

幻灯片没有说,但红色的方块表示不赞成的行为。 也就是说,如果您不想依赖已弃用的行为,则在声明您的析构函数或其中一个副本成员(基本上遵循C ++ 98/03“3规则”)的情况下声明两个副本成员

我build议阅读幻灯片,以获得这张桌子的逐步build设,并详细解释我们现在如何以及为什么这样做。

其他演示可以在这里find: http : //accu.org/index.php/articles/1901