Many classes in the c++ standard library now have move constructors, for example -
thread::thread(thread&& t)
But it appears that std::mutex does not. I understand that they can't be copied, but it seems to make sense to be able to return one from a "make_mutex" function for example. (Not saying it's useful, just that it makes sense)
Is there any reason why std::mutex doesn't have a move constructor?
On the other hand, while right now std::mutex is not movable, it is very easy to 'return' one from a function: return an std::unique_ptr<std::mutex> instead. This still pays the costs of dynamic allocation but only in one spot.
std::move is actually just a request to move and if the type of the object has not a move constructor/assign-operator defined or generated the move operation will fall back to a copy.
std::move. std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.
Well... mainly because I don't think they should move. Literally.
In some OS-es a mutex might be modeled as a handle (so you could copy them) but IIRC a pthreads mutex is manipulated in-place. If you are going to relocate that, any threadsafety is going fly right out of the window (how would the other threads know that the mutex had just changed it's memory address...)?
Remember that C++ takes the "don't pay for what you don't use" philosophy to heart. Let's consider for instance an imaginary platform that uses an opaque type to represent a mutex; let's call that type mutex_t
. If the interface to operate on that mutex uses mutex_t*
as arguments, for instance like void mutex_init(mutex_t* mutex);
to 'construct' a mutex, it might very well the case that the address of the mutex is what's used to uniquely identify a mutex. If this is the case, then that means that mutex_t
is not copyable:
mutex_t kaboom() { mutex_t mutex; mutex_init(&mutex); return mutex; // disaster }
There is no guarantee here when doing mutex_t mutex = kaboom();
that &mutex
is the same value as &mutex
in the function block.
When the day comes that an implementor wants to write an std::mutex
for that platform, if the requirements are that type be movable, then that means the internal mutex_t
must be placed in dynamically-allocated memory, with all the associated penalties.
On the other hand, while right now std::mutex
is not movable, it is very easy to 'return' one from a function: return an std::unique_ptr<std::mutex>
instead. This still pays the costs of dynamic allocation but only in one spot. All the other code that doesn't need to move an std::mutex
doesn't have to pay this.
In other words, since moving a mutex isn't a core operation of what a mutex is about, not requiring std::mutex
to be movable doesn't remove any functionality (thanks to the non-movable T
=> movable std::unique_ptr<T>
transformation) and will incur minimal overhead costs over using the native type directly.
std::thread
could have been similarly specified to not be movable, which would have made the typical lifetime as such: running (associated to a thread of execution), after the call to the valued constructor; and detached/joined (associated with no thread of execution), after a call to join
or detach
. As I understand it an std::vector<std::thread>
would still have been usable since the type would have been EmplaceConstructible
.
edit: Incorrect! The type would still need to be movable (when reallocating after all). So to me that's rationale enough: it's typical to put std::thread
into containers like std::vector
and std::deque
, so the functionality is welcome for that type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With