15

考虑以下类:

class A
{
public:
   std::string field_a;
   std::string field_b;
}

现在考虑以下复制结构:

A a1(a2);

A尽管缺少显式复制构造函数,复制构造仍将充分复制,因为std::string编译器生成的隐式复制构造函数将调用 for 的复制构造函数。

我想知道的是,搬家施工也是如此吗?

编辑这里的测试表明:

A a2(std::move(a1));

实际上会导致复制构造,除非特定的移动构造函数:

A( A && other ) : a(std::move(other.a)) {}

被定义为。

编辑 编辑 我联系了 Stephan T Lavavej 并问他为什么 VC 2012 似乎没有遵循 12.8 草案关于隐式移动构造函数生成的规定。他好心解释:

它更像是一个“尚未实现的功能”而不是一个错误。VC 目前实现了我所说的右值引用 v2.0,其中移动 ctors/assigns 永远不会隐式生成,也不会影响复制 ctors/assigns 的隐式生成。C++11 指定右值引用 v3.0,这是您正在查看的规则。

4

2 回答 2

16

是的,来自 C++11 草案,12.8:

如果类 X 的定义没有显式声明移动构造函数,当且仅当

  • X 没有用户声明的复制构造函数,
  • X 没有用户声明的复制赋值运算符,
  • X 没有用户声明的移动赋值运算符,
  • X 没有用户声明的析构函数,并且
  • 移动构造函数不会被隐式定义为已删除。

最后一个条件将在稍后更详细地指定:

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

  • 具有非平凡对应构造函数的变体成员,并且 X 是类联合类,
  • 类类型 M(或其数组)的非静态数据成员,因为重载决议 (13.3) 应用于 M 的相应构造函数时,会导致歧义或从默认值中删除或无法访问的函数,因此无法复制/移动构造函数,
  • 无法复制/移动的直接或虚拟基类 B,因为应用于 B 的相应构造函数的重载解析 (13.3) 会导致歧义或从默认构造函数中删除或无法访问的函数,
  • 具有从默认构造函数中删除或不可访问的析构函数的类型的任何直接或虚拟基类或非静态数据成员,
  • 对于复制构造函数,右值引用类型的非静态数据成员,或
  • 对于移动构造函数,非静态数据成员或直接或虚拟基类,其类型没有移动构造函数且不可轻易复制。

简而言之,如果出现以下情况,将隐式声明移动构造函数:

  1. 该类没有用户声明的任何其他特殊成员函数。
  2. 移动构造函数可以通过移动它的所有成员和基数来实现。

你的班级显然符合这些条件。

于 2012-11-12T14:34:15.733 回答
6

如果可以并且没有用户定义的复制构造函数,编译器会合成一个移动构造函数。如果存在复制构造函数,则不合成移动构造函数的限制旨在避免破坏现有代码。当然,所有成员都需要是可移动的。确切的规则涉及更多。

于 2012-11-12T14:01:20.103 回答