Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should a move constructor take a const or non-const rvalue reference?

In several places I've seen the recommended signatures of copy and move constructors given as:

struct T {     T();     T(const T& other);     T(T&& other); }; 

Where the copy constructor takes a const reference, and the move constructor takes a non-const rvalue reference.

As far as I can see though, this prevents me taking advantage of move semantics when returning const objects from a function, such as in the case below:

T generate_t() {     const T t;     return t; } 

Testing this with VC11 Beta, T's copy constructor is called, and not the move constructor. Even using return std::move(t); the copy constructor is still called.

I can see how this makes sense, since t is const so shouldn't bind to T&&. Using const T&& in the move constructor signature works fine, and makes sense, but then you have the problem that because other is const, you can't null its members out if they need to be nulled out - it'll only work when all members are scalars or have move constructors with the right signature.

It looks like the only way to make sure the move constructor is called in the general case to have made t non-const in the first place, but I don't like doing that - consting things is good form and I wouldn't expect the client of T to know that they had to go against that form in order to increase performance.

So, I guess my question is twofold; first, should a move constructor take a const or non-const rvalue reference? And second: am I right in this line of reasoning? That I should stop returning things that are const?

like image 785
Ben Hymers Avatar asked May 26 '12 22:05

Ben Hymers


People also ask

Is it necessary to have const for a reference in copy constructor?

When we create our own copy constructor, we pass an object by reference and we generally pass it as a const reference. One reason for passing const reference is, we should use const in C++ wherever possible so that objects are not accidentally modified.

Can you Std move const reference?

"std::move" should only be used where moving can happenWhen passing the result of std::move as a const reference argument. In this case, no object will be moved since it's impossible to call the move constructor from within the function.

Can a const reference be bound to a non-const object?

No. A reference is simply an alias for an existing object. const is enforced by the compiler; it simply checks that you don't attempt to modify the object through the reference r .

When should we use a const reference and why?

Pass Using Const Reference in C++ Now, we can use the const reference when we do not want any memory waste and do not change the variable's value. The above code will throw a compile error as num = num +10 is passed as a const reference.


2 Answers

It should be a non-const rvalue reference.

If an object is placed in read-only memory, you can't steal resources from it, even if its formal lifetime is ending shortly. Objects created as const in C++ are allowed to live in read-only memory (using const_cast to try to change them results in undefined behavior).

like image 136
Ben Voigt Avatar answered Oct 01 '22 11:10

Ben Voigt


A move constructor should normally take a non-const reference.

If it were possible to move from a const object it would usually imply that it was as efficient to copy an object as it was to "move" from it. At this point there is normally no benefit to having a move constructor.

You are also correct that if you have a variable that you are potentially going to want to move from then it will need to be non-const.

As I understand it this is the reason that Scott Meyers has changed his advice on returning objects of class type by value from functions for C++11. Returning objects by const qualified value does prevent unintentionally modification of a temporary object but it also inhibits moving from the return value.

like image 27
CB Bailey Avatar answered Oct 01 '22 12:10

CB Bailey