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

Mr.*_*C64 34 c++ move-semantics c++11

在C++ 98中,C++编译器可以通过成员方式复制自动生成复制构造函数和复制赋值运算符,例如

struct X {
    std::string s;
    std::vector<int> v;
    int n;
};
Run Code Online (Sandbox Code Playgroud)

编译器使用成员方式复制自动生成复制构造函数和复制赋值运算符X.

但是,C++ 11中的移动语义如何改变?

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

是否存在自动生成移动操作的情况?

Kla*_*aim 54

Nikos Athanasiou给出了一个很好的答案,但我想添加这个我认为非常有用的工具.

以下是来自ACCU 2014会议的Howard Hinnant的演讲"您想要了解移动语义的一切(以及一些)"的截图,我认为这是对特殊成员自动生成规则的一个非常好的提醒:

在此输入图像描述

Hinnant先生从评论中澄清:

幻灯片没有说明,但红色方块表示弃用行为.即如果您不想依赖于已弃用的行为,则声明您的析构函数或其中一个复制成员(基本遵循C++ 98/03"3规则"),然后声明两个复制成员

我建议您阅读幻灯片以获得此表的渐进式构建,并详细说明我们现在如何以及为什么这样做.

其他演示文稿可以在那里找到:http://accu.org/index.php/articles/1901

  • +1和信息:幻灯片没有说出来,但红色方块表示已弃用的行为.即如果您不想依赖于已弃用的行为,则声明您的析构函数或其中一个复制成员(基本遵循C++ 98/03"3规则"),然后声明两个复制成员. (5认同)
  • 这将是一张漂亮的海报 (3认同)

Nik*_*iou 28

从标准Ch.12 - 特别会员职能

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

9.如果类X的定义没有显式地声明一个移动构造函数,那么当且仅当一个移动构造函数被隐式声明为默认值时

- X没有用户声明的复制构造函数,

- X没有用户声明的复制赋值运算符,

- X没有用户声明的移动赋值运算符,和

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

[注意:当未隐式声明或显式提供移动构造函数时,否则将调用移动构造函数的表达式可能会调用复制构造函数. - 尾注]

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

11.隐式声明的复制/移动构造函数是其类的内联公共成员.如果X具有以下内容,则将类X的默认复制/移动构造函数定义为已删除(8.4.3):

- 具有非平凡对应构造函数的变体成员,X是类似联合的类,

- 类型M(或其数组)的非静态数据成员,由于应用于M的相应构造函数的重载解析(13.3),无法复制/移动,导致模糊或被删除或无法访问的函数默认构造函数,

- 无法复制/移动的直接或虚拟基类B,因为重载解析(13.3),应用于B的相应构造函数,导致模糊或从默认构造函数中删除或无法访问的函数,

- 具有从默认构造函数中删除或无法访问的析构函数的任何类型的直接或虚拟基类或非静态数据成员,或者,

- 对于复制构造函数,rvalue引用类型的非静态数据成员.超载解析(13.3,13.4)忽略定义为已删除的默认移动构造函数.

[注意:删除的移动构造函数否则会干扰rvalue的初始化,而rvalue可以使用复制构造函数. - 尾注]


关于它的复杂性*

规则可能有点压倒性.使用某种技术来绕过复杂性是很好.例如:

  1. 利用零规则来简化大多数类的编写.
  2. (在隐式删除时)明确默认有问题的特殊成员函数; 如果它被隐式定义为删除,编译器会抱怨.

*我自己评论中的观点(1)和dyp(2)

  • 你可以明确地默认它们; 如果他们被隐式定义为删除,编译器会抱怨. (7认同)