"Mutable is used to specify that the member does not affect the externally visible state of the class (as often used for mutexes, memo caches, lazy evaluation, and access instrumentation)." [Reference: cv (const and volatile) type qualifiers, mutable specifier]
This sentence made me wonder:
"Guideline: Remember the “M&M rule”: For a member-variable, mutable and mutex (or atomic) go together." [Reference: GotW #6a Solution: Const-Correctness, Part 1 (updated for C ++11/14)]
I understand why “M&M rule” applies to std::mutex
data-member: to allow const-functions to be thread-safe despite they lock/unlock the mutex data-member, but does “M&M rule” applies also to std::atomic
data-member?
You got it partly backwards. The article does not suggest to make all atomic members mutable. Instead it says:
(1) For a member variable, mutable implies mutex (or equivalent): A mutable member variable is presumed to be a mutable shared variable and so must be synchronized internally—protected with a mutex, made atomic, or similar.
(2) For a member variable, mutex (or similar synchronization type) implies mutable: A member variable that is itself of a synchronization type, such as a mutex or a condition variable, naturally wants to be mutable, because you will want to use it in a non-const way (e.g., take a std::lock_guard) inside concurrent const member functions.
(2) says that you want a mutex member mutable. Because typically you also want to lock the mutex in const
methods. (2) does not mention atomic members.
(1) on the other hand says that if a member is mutable, then you need to take care of synchronization internally, be it via a mutex or by making the member an atomic
. That is because of the bullets the article mentions before:
If you are implementing a type, unless you know objects of the type can never be shared (which is generally impossible), this means that each of your const member functions must be either:
- truly physically/bitwise const with respect to this object, meaning that they perform no writes to the object’s data; or else
- internally synchronized so that if it does perform any actual writes to the object’s data, that data is correctly protected with a mutex or equivalent (or if appropriate are atomic<>) so that any possible concurrent const accesses by multiple callers can’t tell the difference.
A member that is mutable is not "truly const", hence you need to take care of synchronization internally (either via a mutex or by making the member atomic).
TL;DR: The article does not suggest to make all atomic members mutable. It rather suggests to make mutex members mutable and to use internal synchronization for all mutable members.