c++11 move constructor question

Started by
7 comments, last by King Mir 10 years, 2 months ago

Suppose I have the following:

class Test {};

Test a;

vector<Test> v;

v.push_back(std::move(a));

Basically,now a has been moved to the vector(so it is a part of the vector now),but,what happens if I try to access the original a?(not the one that is in the vector now?)

Advertisement

That depends on the implementation of the move constructor and the data you're trying to access. The variable a has not been 'moved', it still resides in the same memory location occupying the same space. The variable that's been constructed in the vector can steal contents from a. If for example a holds a pointer to an array, this pointer could be copied and then set to null for a, accessing the pointer through a would then result in a nullpointer error.

After std::move, 'a' is left in a valid but unspecified state. (http://en.cppreference.com/w/cpp/utility/move)

Correct me if I'm wrong, but there's little point in calling std::move on an lvalue (as is the case in your code).

It'd make more sense like this:


vector<Test> v;
v.push_back(std::move(Test()));

see below.

"I would try to find halo source code by bungie best fps engine ever created, u see why call of duty loses speed due to its detail." -- GettingNifty

Correct me if I'm wrong, but there's little point in calling std::move on an lvalue (as is the case in your code).

It'd make more sense like this:




vector<Test> v;
v.push_back(std::move(Test()));


You are wrong. In your example you don't even need the std::move because 'Test()' is an xvalue as an expiring temporary. The whole point of std::move is to allow moving of what would usually be lvalues.

Correct me if I'm wrong, but there's little point in calling std::move on an lvalue (as is the case in your code).

It'd make more sense like this:



vector<Test> v;
v.push_back(std::move(Test()));

You are wrong. In your example you don't even need the std::move because 'Test()' is an xvalue as an expiring temporary. The whole point of std::move it to allow it on what would usually be lvalues.

Also, if the intention is to construct a temporary object just to pass it to push_back, you should instead use emplace_back to construct it in-place inside the vector and skip the temporary object entirely.

Suppose I have the following:

class Test {};

Test a;
vector<Test> v;
v.push_back(std::move(a));

Basically,now a has been moved to the vector(so it is a part of the vector now),but,what happens if I try to access the original a?(not the one that is in the vector now?)

std::move is just a cast, converting "a" to an rvalue. Since Test does not implement an explicit move constructor, it's just copy constructed. And since Test has no members, that's a no-op.

Standard library objects that are moved are generally specified to become objects that you cannot do anything with but destroy. Some standard classes may have more defined semantics, and in many cases the use of a moved from object can be predictably relied upon. However, any classes you write can have whatever state after a move that you code up. Those semantics are dictated by your implementation of the move constructor.

Another thing to be aware of when using moveable objects with an std::vector is that the noexcept state of the move constructor can effect when objects can be moved on reallocation. So if you write an object that can be moved and put in a vector, remember to specify if it cannot throw.

Since Test does not implement an explicit move constructor, it's just copy constructed. And since Test has no members, that's a no-op.


Setting aside the empty-class test case problem, according to this page the compiler should implicitly generate a move constructor. So in my understanding, if the test class contained expensive to copy members (like complex std::containers) the compiler would have generated a move constructor which could have been used.

I'm happy to be corrected though.

Since Test does not implement an explicit move constructor, it's just copy constructed. And since Test has no members, that's a no-op.


Setting aside the empty-class test case problem, according to this page the compiler should implicitly generate a move constructor. So in my understanding, if the test class contained expensive to copy members (like complex std::containers) the compiler would have generated a move constructor which could have been used.

I'm happy to be corrected though.

No, you're right, good catch.

This topic is closed to new replies.

Advertisement