sircodesalot
sircodesalot

Reputation: 11439

What happens when you move to not an rvalue reference?

So I've been burned by this a couple of times. What is the difference between this:

 Movable&& object = std::move(another_movable);

and this:

 Movable object = std::move(another_movable);

It seems like both should work equally, but I always get inexplicable behavior (properties of the object changing) with the second example. Why is this?

Upvotes: 4

Views: 248

Answers (3)

user45927
user45927

Reputation: 186

as was already said, first is copying a reference. as with all pointer-types you really shouldn't have return-type being an rvalue unless it's on the heap.

however, 2nd is a bit more complicated than just being an rvalue initialization. consider:

Moveable object = another_moveable;

or

Moveable object = function_returning_another_moveable();

seemingly the latter is initialization from a true, non-casted rvalue. but see http://en.cppreference.com/w/cpp/language/copy_elision

and the former actually depends on what constructors Moveable has.

as for unexpected behaviour, this is most likely because of inheritance-loss, so to say. i.e. if another_moveable is only derived from Moveable, Moveable will use rvalue initialization for the Moveable parent of another_moveable only, and whatever data the derived object had is now lost.

just for emphasis: Moveable having an rvalue initialization doesn't mean the other object is merely getting a new reference, rvalue initialization is for data stored on the heap to stay where it was, with only pointers and references in the new objects being copied over from old. rvalue initialization still does copy the whole object, but afterwards it makes sure that when the old object is destroyed, its data on the heap will stay, and this should be done by changing the old object's pointers! the compiler doesn't actually do any of that, the program and the headers used must make sure the expected things are done!

Upvotes: 0

David G
David G

Reputation: 96790

Maybe comparing it to an lvalue-reference version might help:

Object& object = another_object;

Object object  = another_object;

The first is a reference to an lvalue, so no constructors are called. It just refers to the object named another_object, like a pointer. Object object creates a brand new object so the constructors will be called (not assuming copy-elision).

Now rvalue-references are the same, but they are tailored exclusively for rvalues. They now refer to the rvalue from which it is initialized.

Upvotes: 6

R. Martinho Fernandes
R. Martinho Fernandes

Reputation: 234364

Movable&& object = std::move(another_movable);

This makes another reference to the same object as another_movable.

Movable object = std::move(another_movable);

This makes a new object initialized from an rvalue of another_movable.

Upvotes: 5

Related Questions