考虑以下课程:
class A
{
public:
std::string field_a;
std::string field_b;
}
现在考虑以下复制结构:
A a1(a2);
尽管缺少显式的复制构造函数,但复制构造将充分复制A
,因为std::string
的复制构造函数将由编译器生成的隐式复制构造函数调用。
我想知道的是,移动构造也是如此吗?
编辑:测试here显示:
A a2(std::move(a1));
实际上会导致复制构造,除非特定的移动构造函数:
A( A && other ) : a(std::move(other.a)) {}
已定义。
编辑编辑 我谴责了Stephan T Lavavej,并问他为什么VC 2012似乎没有遵循12.8关于隐式移动构造函数生成的草案。他很友好地解释道:
它更像是一个“尚未实现的功能”,而不是一个bug。 VC目前 实现我所称的右值引用v2.0,其中move ctors / assign永远不会隐含生成,永远不会影响 隐含生成复制ctors / assign。 C ++ 11指定rvalue 引用v3.0,这是你正在看的规则。
答案 0 :(得分:9)
是的,来自C ++ 11草案,12.8:
如果类X的定义没有显式声明移动构造函数,则会隐式声明一个 当且仅当
时默认为
- X没有用户声明的复制构造函数,
- X没有用户声明的复制赋值运算符
- X没有用户声明的移动赋值运算符
- X没有用户声明的析构函数,
- 移动构造函数不会被隐式定义为已删除。
后面的条件将在后面详细说明:
隐式声明的复制/移动构造函数是其类的内联公共成员。如果X具有以下内容,则将类X的默认复制/移动构造函数定义为已删除(8.4.3):
- 具有非平凡对应构造函数的变体成员,X是类似联合的类,
- 类型为M(或其数组)的非静态数据成员,由于无法复制/移动 重载决策(13.3),应用于M的相应构造函数,导致模糊或a 从默认构造函数中删除或无法访问的函数,
- 由于重载决策(13.3)而无法复制/移动的直接或虚拟基类B. 应用于B的相应构造函数,导致歧义或被删除的函数或 无法从默认构造函数中获取,
- 具有已删除的析构函数的类型的任何直接或虚拟基类或非静态数据成员 或者从违约的构造函数中无法访问,
- 表示复制构造函数,rvalue引用类型的非静态数据成员,或
- 用于移动构造函数,非静态数据成员或直接或虚拟基类,其类型不具有移动构造函数,并且不易于复制。
简单地说,如果出现以下情况,将隐式声明移动构造函数:
你的班级显然符合这些条件。
答案 1 :(得分:5)
如果可以,并且没有用户定义的复制构造函数,编译器会合成移动构造函数。如果存在复制构造函数则不合成移动构造函数的限制旨在避免破坏现有代码。当然,所有成员都需要移动。确切的规则涉及更多。