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

时间:2014-06-21 15:12:29

标签: c++ c++11 move-semantics

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

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

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

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

移动 构造函数 移动 赋值运算符< / strong> 自动生成,如复制构造函数和复制赋值运算符?

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

2 个答案:

答案 0 :(得分:52)

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

以下是来自ACCU 2014大会的Howard Hinnant的演讲"Everything You Ever Wanted To Know About Move Semantics (and then some)"的截图,我认为这是对特殊成员自动生成规则的一个很好的提醒:

enter image description here

Hinnant先生从评论中澄清:

  

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

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

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

答案 1 :(得分: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. 利用rule of zero简化大部分课程的写作。
  2. (On implicitly deleted)显式默认有问题的特殊成员函数;如果它被隐式定义为已删除,编译器会抱怨。
  3. *我自己(1)和dyp(2)

    在评论中提出的观点