What is the difference between these two terms, and why do I need mutable
?
5 Answers
"Physical" constness comes from declaring an object const
, and could, in principle, be enforced by placing the object in read-only memory, so it cannot change. Attempting to change it will cause undefined behaviour; it might change, or it might not, or it might trigger a protection fault, or it might melt the memory chip.
"Logical" constness comes from declaring a reference or pointer const
, and is enforced by the compiler. The object itself may or may not be "physically" const, but the reference cannot be used to modify it without a cast. If the object is not "physically" const, then C++ allows you to modify it, using const_cast
to circumvent the protection.
A mutable
class member can be modified even if the class object itself (or the reference or pointer used to access it) is const
. Examples of good uses of this are a mutex that must be locked during a read operation, and a cache to store the result of an expensive read operation. In both cases, the operation itself should be a const
function (since it doesn't affect the visible state of the object), but it needs to modify the mutex or the cache, so these need to be mutable
. It can also be abused to make the object visibly change when logically it shouldn't, so use it with care; only declare members mutable
if they don't form part of the externally visible state.

- 249,747
- 28
- 448
- 644
-
2That reads very well :-), but is very wrong :-(. ""Physical" constness comes from declaring an object const" - `const` won't guarantee your "physical constness": members may still be `mutable` and changed at run-time. Because this is allowed, the compiler/linker etc. will not place such objects in read-only memory by default, even if they're `static const`. If they're forced there through some non-Standard compiler/linker/loader flags, then the programmer must manually avoid `mutable` members. The distinction you draw between objects and pointer/references is actually irrelevant. – Tony Delroy Jul 28 '11 at 01:49
-
2@TonyDelroy - I took Mike's response involving "placing the object in read-only memory" as a rhetorical (and rhetorically effective) statement to make a point about the difference between physical and logical `const`-ness, not as a statement that compilers will actually do this; nor did he state that compilers *will* do this. Also, I disagree that his distinction between pointers and references is irrelevant. The answer is conceptually solid and correct. TonyDelroy is, in my opinion, not correct when he states that the answer is "very wrong". – Dan Nissenbaum May 29 '12 at 05:02
-
1_A mutable class member can be modified even if the class itself (or the reference or pointer used to access it) is const_. Classes are **not** const. Only an instance can be const. A symbol's type describes the instance's constness as seen from that symbol name. A good explanation otherwise. – Adrian Jun 04 '14 at 20:00
-
@Adrian: Yes, that's what I meant. Sorry for the slightly ambiguous wording. – Mike Seymour Jun 05 '14 at 15:02
-
you clarify the concept very well, +1 for that. – HDJEMAI Mar 22 '17 at 03:05
You need mutable
when there are fields in an object that can be considered "internal", i.e. any external user of the class cannot determine the value of these fields. The class might need to write to these fields even though the instance is considered constant, i.e. not changing.
Consider a hard drive; its cache is an example of such state. The cache is written to when data is read from the actual disk.
This is not possible to express cleanly in C++ without making the corresponding members mutable
, to allow them to be changed even in methods marked const
. As pointed out in a comment, you can always reach for the hammer and use a const_cast<>
to remove the const
-ness, but that is of course cheating. :)

- 391,730
- 64
- 469
- 606
-
5Another such example would be a mutex in an object shared by different threads. A read operation does not modify the object, but the mutex must be acquired and released in the process. The mutex member object clearly changes during the operation, even if the result of the operation does not change the object per-se. An operation is const on an object if the perceived state remains unmodified, even if internal elements change. – David Rodríguez - dribeas Sep 30 '10 at 12:25
-
can You please give me small example(code) which shows what things I can do with mutable and can't with const, which also shows difference between logic and physical const'ness I found some explanations in google but can't find good example, with cache a little bit difficult to understand – rookie Sep 30 '10 at 12:34
-
_This is not possible to express in C++ without making the corresponding members `mutable`_. That statement is incorrect, at it **can** be accomplished (and has in the past) by removing the constness by way of casting the object or the member. The keyword `mutable` came in after, when the idea of logical constness was realised because programmers were removing the constness of objects manually to gain this effect, making it more maintainable and enforceable. See [here](http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter08_025.html). – Adrian Jun 04 '14 at 20:08
-
Scott Meyers, Effective C++, Item 3:
Use const
whenever possible
has an excellent discussion (with examples) on this topic. Its hard to write better than Scott!
Note also that physical-constness is also known as bitwise-constness.

- 19,750
- 10
- 51
- 60
Some code for people who want to try out the effects of physical constness theirselfes:
#include <type_traits>
using namespace std;
using type = int const;
type &f();
int main()
{
const_cast<remove_const_t<type> &>(f()) = 123;
}
#if defined(__GNUC__) || defined(__llvm__)
__attribute__((noinline))
#elif defined(_MSC_VER)
__declspec(noinline)
#endif
type &f()
{
static type i = 0;
return i;
}
Under Linux and Windows this program crashes until you drop the const-specifier with type.

- 2,817
- 9
- 22
I respectfully disagree with Mike Seymour's answer:
A member function of a class can be defined as a const function, meaning that it will not modify any internal state of the object (except for members that are marked mutable, which becomes an important issue when we talk later about "logical" const-ness). That is the actual definition of "physical" const-ness. But even though a function is marked const, it may be logically modifying the objects state. Consider the following example:
#include <iostream>
using namespace std;
class Foo
{
private:
int *ip;
public:
Foo(int i) {
ip = new int(i);
}
virtual ~Foo() {
delete ip;
}
void modifyState(int i) const {
*ip = i;
}
int getI(void) const {
return *ip;
}
};
int main(int argc, char *argv[])
{
Foo foo(7);
cout << foo.getI() << endl;
foo.modifyState(9);
cout << foo.getI() << endl;
return 0;
}
Prints:
7
9
Member function modifyState
does not modify member ip
, so it satisfies the requirements for physical const-ness. But who can argue that since it is modifying what ip
points to that the logical state has not been changed? So even though this function satisfies the requirements for physical cont-ness, it does not satisfy logical const-ness since what function getI
will return has been changed by the call to modifyState
.
Conversely, we can physically modify an object's member, but the state of the object as it appears to the outside world via its interface has not changed. Consider the following example where const functions getCelsiusTemperature
and getFahrenheitTemperature
modify mutable state but do not modify the object's logical state:
#include <iostream>
using namespace std;
class Temperature
{
private:
mutable float temperature;
mutable bool is_celsius;
public:
Temperature(double temperature, bool is_celsius=true) {
this->temperature = temperature;
this->is_celsius = is_celsius;
}
double getCelsiusTemperature(void) const {
if (!this->is_celsius) {
// convert to Celsius:
this->temperature = (this->temperature - 32.0) * 5.0 / 9.0;
this->is_celsius = true;
}
return this->temperature;
}
const double getFahrenheitTemperature(void) const {
if (this->is_celsius) {
// convert to Fahrenheit:
this->temperature = this->temperature * 9.0 / 5.0 + 32.0;
this->is_celsius = false;
}
return this->temperature;
}
};
int main(int argc, char *argv[])
{
const Temperature t(100, true);
cout << t.getCelsiusTemperature() << endl;
cout << t.getFahrenheitTemperature() << endl;
cout << t.getCelsiusTemperature() << endl;
return 0;
}
Prints:
100
212
100

- 38,656
- 3
- 37
- 60