After watching Herb Sutter\'s talk You Don\'t Know const and mutable, I wonder whether I should always define a mutex as mutable? If yes, I guess the same holds for any sync
I just watched the talk, and I do not entirely agree with what Herb Sutter is saying.
If I understand correctly, his argument is as follows:
[res.on.data.races]/3
imposes a requirement on types that are used with the standard library -- non-const member functions must be thread-safe.
Therefore const
is equivalent to thread-safe.
And if const
is equivalent to thread-safe, the mutable
must be equivalent to "trust me, even the non-const members of this variable are thread-safe".
In my opinion, all three parts of this argument are flawed (and the second part is critically flawed).
The problem with 1
is that [res.on.data.races]
gives requirements for types in the standard library, not types to be used with the standard library. That said, I think it is reasonable (but not entirely clear-cut) to interpret [res.on.data.races]
as also giving requirements for types to be used with the standard library, because it would be practically impossible for a library implementation to uphold the requirement to not modify objects through const
references if const
member functions were able to modify objects.
The critical problem with 2
is that while it is true (if we accept 1
) that const
must imply thread-safe, it is not true that thread-safe implies const
, and so the two are not equivalent. const
still implies "logically immutable", it is just that the scope for "logically immutability" has expanded to require thread-safety.
If we take const
and thread-safe to be equivalent, we lose the nice feature of const
which is that it allows us to easily reason about code by seeing where values can be modified:
//`a` is `const` because `const` and thread-safe are equivalent.
//Does this function modify a?
void foo(std::atomic const& a);
Furthermore, the relevant section of [res.on.data.races]
talks about "modifies", which can be reasonably interpreted in the more general sense of "changes in an externally observable way", rather than just "changes in a thread-unsafe way".
The problem with 3
is simply that it can only be true if 2
is true, and 2
is critically flawed.
So to apply this to your question -- no, you should not make every internally synchronised object mutable
.
You should reserve mutable
for member variables that do not affect the externally visible state of the object. On the other hand (and this is the key point that Herb Sutter makes in his talk), if you have a member that is mutable for some reason, that member must be internally synchronised, otherwise you risk making const
not imply thread-safe, and this would cause undefined behaviour with the standard library.