I'm reading Functional Programming in C++ from Ivan Čukić, and I am having a hard time interpreting a point in the summary of Chapter 5:
- When you make a member function
const
, you promise that the function won't change any data in the class (not a bit of the object will change), or that any changes to the object (to members declared asmutable
) will be atomic as far as the users of the object are concerned.
If the part in italic was simply are limited to members declared as mutable
I would have been happy with it. However, this rewording of mine seems to correspond to what the author put in parenthesis. What is out of parenthesis is what is puzzling me: what is the meaning of atomic in that sentence?
The author is making a claim about best practices, not about the rules of the language.
You can write a class in which const
methods alter mutable
members in ways that are visible to the user, like this:
struct S {
mutable int value = 0;
int get() const {
return value++;
}
};
const S s;
std::cout << s.get(); // prints 0
std::cout << s.get(); // prints 1
// etc
You can do that, and it wouldn't break any of the rules of the language. However, you shouldn't. It violates the user's expectation that the const
method should not change the internal state in an observable way.
There are legitimate uses for mutable
members, such as memoization that can speed up subsequent executions of a const
member function.
The author suggests that, as a matter of best practices, such uses of mutable
members by const
member functions should be atomic, since users are likely to expect that two different threads can call const
member functions on an object concurrently.
If you violate this guideline, then you're not directly breaking any rules of the language. However, it makes it likely that users will use your class in a way that will cause data races (which are undefined behaviour). It takes away the user's ability to use the const
qualifier to reason about the thread-safety of your class.