The mutable
keyword is a way to pierce the const
veil you drape over your objects. If you have a const reference or pointer to an object, you cannot modify that object in any way except when and how it is marked mutable
.
With your const
reference or pointer you are constrained to:
- only read access for any visible data members
- permission to call only methods that are marked as
const
.
The mutable
exception makes it so you can now write or set data members that are marked mutable
. That's the only externally visible difference.
Internally those const
methods that are visible to you can also write to data members that are marked mutable
. Essentially the const veil is pierced comprehensively. It is completely up to the API designer to ensure that mutable
doesn't destroy the const
concept and is only used in useful special cases. The mutable
keyword helps because it clearly marks data members that are subject to these special cases.
In practice you can use const
obsessively throughout your codebase (you essentially want to "infect" your codebase with the const
"disease"). In this world pointers and references are const
with very few exceptions, yielding code that is easier to reason about and understand. For a interesting digression look up "referential transparency".
Without the mutable
keyword you will eventually be forced to use const_cast
to handle the various useful special cases it allows (caching, ref counting, debug data, etc.). Unfortunately const_cast
is significantly more destructive than mutable
because it forces the API client to destroy the const
protection of the objects (s)he is using. Additionally it causes widespread const
destruction: const_cast
ing a const pointer or reference allows unfettered write and method calling access to visible members. In contrast mutable
requires the API designer to exercise fine grained control over the const
exceptions, and usually these exceptions are hidden in const
methods operating on private data.
(N.B. I refer to to data and method visibility a few times. I'm talking about members marked as public vs. private or protected which is a totally different type of object protection discussed here.)