In Scott Meyers' "Effective Modern C++", he writes:
It's worth nothing that because
std::mutex
is a move-only type (i.e., a type that can be moved, but not copied), a side effect of addingm
toPolynomial
is thatPolynomial
loses the ability to be copied. It can still be moved, however.
Here, he adds a std::mutex m
as a member variable to a class Polynomial
in the context of explaining why one should protect access to const member variable of a class(while multi-threading). I understood the concept he explained. but one thing which I need to have some more explanation is "why Adding a move only type to a class makes that class as move only type not copy-able"?, why types like std::mutex
and std::atomic
is move only type by default? how can we get over with it if we want to perform copy operation even when adding move only type of variable to our class?
std::mutex
is not copyable only because the standard says so. They could probably have written a std::mutex
that was copyable, but they decided not to.
As a guess, a non-copyable std::mutex
might be more efficient, safer, or easier to understand.
As an example, here is why it might be safer/easier to understand: What does it mean to copy a std::mutex
that is locked? I, personally, have no idea what the right answer is; I suspect that the right answer is "that is nonsense". There is no "answer of least surprise".
Instead of having a surprising answer in concurrency code, by blocking copy we avoid the question. People storing a mutex who want to copy have to decide themselves what they want it to do.
C++ will under some circumstances automatically generate a copy constructor. Under more circumstances it will let you do MyClass(MyClass const&)=default
and write one when you ask for it.
If your class contains a non-copyable class, it won't generate one, and you cannot ask for it. This is because the generated copy constructor basically copies its members; if you cannot copy a member, it cannot generate a copy constructor.
So mutex
cannot be copied because the standard says so.
If a struct or class contains a non-copyable member, the default copy constructor cannot be used. You have to write one yourself explicitly.
If your type needs to store a mutex
, one approach to prevent the headache of having to maintain a copy ctor that manually copies all of its other members is to stick your non-mutex
state into a sub-struct, and then use its default copy. Then you decide what to do with the mutex
during the copy, and your copy ctor (and assignment copy operator) remain simple.
struct bob_with_mutex {
sturct bob_simple_data {
int x, y, z;
std::vector<char> buff;
};
bob_simple_data data;
std::mutex m;
bob_with_mutex( bob_with_mutex const& o ):
data(o.data)
{}
bob_with_mutex& operator=( bob_with_mutex const& o )
{
data = o.data;
return *this;
}
};
the type bob
has a mixture of a mutex and some data. The data is stored in a sub-structure. The copy ctor of bob_with_mutex
cannot be defaulted, but it simply says "copy the data, and nothing else".
The copy of the bob
has its own mutex.