2

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 adding m to Polynomial is that Polynomial 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?

Barry
  • 286,269
  • 29
  • 621
  • 977
RaGa__M
  • 2,550
  • 1
  • 23
  • 44
  • Is your question "why is `std::mutex` noncopyable" or is your question "why does adding a noncopyable member make the class noncopyable"? – Barry Mar 29 '16 at 13:10
  • Barry, Getting answer for Both question fulfill me – RaGa__M Mar 29 '16 at 13:12
  • 1
    How to write the copy and move members for types containing a `mutex`: http://stackoverflow.com/a/29988626/576911 – Howard Hinnant Mar 29 '16 at 14:32
  • Note: std::mutex is not moveable or copyable. – Nevin Mar 29 '16 at 15:00
  • I am reading the same book and that's how I land up here because of the confusion. Thank you for listing out this question and also thank you @Barry for pointing out that it was a mistake in his book. – Naresh Oct 06 '22 at 20:23

3 Answers3

3

"why Adding a move only type to a class makes that class as move only type not copy-able"

This is not entierly true. adding non copyable member variable prevents you from writing something like Type (const Type& t) = default; , but you can still implement you own copy constructor which ignores the non copyable member

class Type{

int integer;
std::mutex m;

public:
Type() = default;
Type(const Type& rhs): integer (rhs.integer){}

}

Other than this, you can find numerous examples of objects that contain move-only members, but they are themselves non movable, simply because the developer deleted the move constructor.

why types like std::mutex and std::atomic is move only type by default?

Neither of them implement move constructor. this is a wrong statement.

David Haim
  • 25,446
  • 3
  • 44
  • 78
  • David thanks! but were you saying that std::mutex is not a move only type?its seems contradict than what was i read. – RaGa__M Mar 29 '16 at 13:14
  • if you copy exactly the paragraph you understood that a mutex is either movable/copiable we will be able to elaborate further – David Haim Mar 29 '16 at 13:18
  • David when i look into the constructor of Std::Mutex it says the mutex( const mutex& ) = delete; so obviously there could be the possibility for move special member function getting generated, was i correct? – RaGa__M Mar 29 '16 at 13:21
  • 2
    This is listed in the errata (http://www.aristeia.com/BookErrata/emc++-errata.html), just a bug in the book. Credit to our very own @K-ballo, I believe. – Barry Mar 29 '16 at 13:22
1

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.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • "Neither std::mutex nor std::atomics are move-only. The are neither copyable nor movable, so classes containingthem are rendered both uncopyable and unmovable"what about this point? – RaGa__M Mar 29 '16 at 13:57
  • 1
    @RichardGeorge Oops. Removed "move-only", replaced with "non-copyable". A class containing a non-copyable member can be copied, but *the default generated copy constructor is implicitly deleted*. – Yakk - Adam Nevraumont Mar 29 '16 at 14:00
  • can you elaborate your last block of lines with a simple syntactic structure because i couldn't get it? – RaGa__M Mar 29 '16 at 14:22
  • Thanks Yaak!! for the explanation of substructure. – RaGa__M Mar 29 '16 at 15:24
-1

One possibility is to change the mutex type to a pointer to a mutex. You can copy the pointer, but there will still only be one copy of the mutex. You may want to use a smart pointer.

Robert Jacobs
  • 3,266
  • 1
  • 20
  • 30