默认移动构造函数和引用成员

Default move constructor and reference members

来自 N3337 的 [12.8] [11]:

The implicitly-defined copy/move constructor for a non-union class X performs a memberwise copy/move of its bases and members. [ Note: brace-or-equal-initializers of non-static data members are ignored. See also the example in 12.6.2. —end note ] The order of initialization is the same as the order of initialization of bases and members in a user-defined constructor (see 12.6.2). Let x be either the parameter of the constructor or, for the move constructor, an xvalue referring to the parameter. Each base or non-static data member is copied/moved in the manner appropriate to its type:

— if the member is an array, each element is direct-initialized with the corresponding subobject of x;

— if a member m has rvalue reference type T&&, it is direct-initialized with static_cast<T&&>(x.m);

— otherwise, the base or member is direct-initialized with the corresponding base or member of x.

这实际上更像是一种澄清,但我看不到该子句中有任何提及左值引用成员的地方。由于它没有提及它们,默认情况下似乎说它们是隐式成员移动的一部分,但以下内容不起作用;

int x = 5;
int& y = x;
int& z(std::move(y)); //error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'std::remove_reference<int&>::type {aka int}'

因此可以安全地假设默认的移动构造函数区分成员是引用并且只是简单地做

int& z = y;

没有调用 std::move?

它由 class 成员访问表达式的规范处理。关键部分是

Let x be either the parameter of the constructor or, for the move constructor, an xvalue referring to the parameter.

换句话说,

的默认移动构造函数
struct X { int x, &y; };

相当于

X::X(X&& other) : x(std::move(other).x), y(std::move(other).y) {}

这里重要的是 class 成员访问表达式 x.m 的结果,其中 m 命名一个非静态数据成员,如果 m 具有引用类型,但如果 x 是右值且 m 具有非引用类型,则为 xvalue。 (参见 [expr.ref]/4。)这确保左值引用成员将用左值初始化。