Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default move constructor and reference members

From [12.8] [11] of N3337:

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.

This is really more of a clarification, but I can't see any mention of lvalue reference members in that clause. Since it doesn't mention them, by default it seems to say that they are part of the implicit memberwise move, yet the following would not work;

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}'

So is it safe to assume that the default move constructor distinguishes that a member is a reference and would simply just do

int& z = y;

with no call to std::move?

like image 698
AntiElephant Avatar asked Oct 27 '15 22:10

AntiElephant


People also ask

What does the default move constructor do?

A move constructor allows the resources owned by an rvalue object to be moved into an lvalue without creating its copy.

Does move constructor call default constructor?

A move constructor in general does not have to provide default initialization. Your move constructor does. A move constructor is still a constructor. And therefore, it must initialize all subobjects.

What is the difference between move constructor and move assignment?

The move assignment operator is different than a move constructor because a move assignment operator is called on an existing object, while a move constructor is called on an object created by the operation. Thereafter, the other object's data is no longer valid.

Does C++ create default move constructor?

In C++, the compiler creates a default constructor if we don't define our own constructor.


1 Answers

It's handled by the specification of class member access expressions. The key part is

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

In other words, a defaulted move constructor for

struct X { int x, &y; };

does the equivalent of

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

The important thing here is that the result of a class member access expression x.m, where m names a non-static data member, is always an lvalue if m has reference type, but an xvalue if x is an rvalue and m has non-reference type. (See [expr.ref]/4.) This ensures that lvalue reference members will be initialized with lvalues.

like image 160
T.C. Avatar answered Oct 10 '22 16:10

T.C.