std::thread Why object is copied twice?

For anything you want to move or avoid copies, prefer move constructors and std::move.

But Why doesn't this happen automatically for me?

Move in C++ is conservative. It generally will only move if you explicitly write std::move(). This was done because move semantics, if extended beyond very explicit circumstances, might break older code. Automatic-moves are often restricted to very careful set of circumstances for this reason.

In order to avoid copies in this situation, you need to shift a around by using std::move(a) (even when passing it into std::thread). The reason it makes a copy the first time around is because std::thread can't guarantee that the value will exist after you have finished constructing the std::thread (and you haven't explicitly moved it in). Thusly, it will do the safe thing and make a copy (not take a reference/pointer to what you passed in and store it: the code has no idea whether or not you'll keep it alive or not).

Having both a move constructor and using std::move will allow the compiler to maximally and efficiently move your structure. If you're using VC++ (with the CTP or not), you must explicitly write the move constructor, otherwise MSVC will (even sometimes erroneously) declare and use a Copy constructor.


The object is copied twice because the object cannot be moved. The standard does not require this, but it is legitimate behavior.

What's happening inside of the implementation is that it seems to be doing a decay_copy of the parameters, as required by the standard. But it doesn't do the decay_copy into the final destination; it does it into some internal, possibly stack, storage. Then it moves the objects from that temporary storage to the final location within the thread. Since your type is not moveable, it must perform a copy.

If you make your type moveable, you'll find that the second copy becomes a move.

Why might an implementation do this, rather than just copying directly into the final destination? There could be any number of implementation-dependent reasons. It may have just been simpler to build a tuple of the function+parameters on the stack, then move that into the eventual destination.

Tags:

C++

C++11