When const Isn't const: A Deep Dive into C++ mutable
In C++, mutable is used to modify class member variables from const member functions. By default, member variables of a class cannot be modified from a const member function.
class MyClass
{
int x;
mutable int y;
void constFunc() const {
x = 10; // Error - cannot modify from const function
y = 20; // Okay - y is mutable
}
};
It is typically used for class member variables that cache calculated values. You want to declare the class object const so the state cannot change, but need to modify cached values.
Example:
A const object that caches calculated values that are expensive to compute. The cached values can be declared mutable so they can be updated even though the object is const.
class MyClass
{
public:
MyClass() : cached_value(computeExpensiveValue()) {}
private:
int computeExpensiveValue()
{
// long computation here
return result;
}
public:
mutable int cached_value;
};
const MyClass obj; // object is const
obj.cached_value = 10; // this is allowed as cached_value is mutable
We use mutable when we want some variables to be modifiable even when accessed through a const reference/pointer to an object. This is useful for things like caching, logging, etc.
const methods cannot modify normal (non-mutable) members. But const methods can modify mutable members.
class MyClass
{
public:
mutable int x;
void mutateX() const {
x = 100; // OK, mutates mutable member
}
};
const MyClass obj;
obj.mutateX();
// obj is const, but mutateX() can still change x since x is mutable
The mutable keyword essentially overrides the constness of a specific member variable. Other member variables will still be const as expected.
Important facts
class MyClass
{
private:
int* ptrData;
public:
void setDataPointer(int* data) const
{
ptrData = data;
}
};
const MyClass obj;
int* newData = new int[100];
obj.setDataPointer(newData); // error
If "MyClass" is const, you cannot call setDataPointer() to change where ptrData points to, since that would mutate the class.
But if you declare ptrData as mutable, you can change what ptrData points to, but not ptrData itself.
class MyClass
{
private:
mutable int* ptrData;
public:
void setDataPointer(int* data) const
{
ptrData = data;
}
};
const MyClass obj;
int* newData = new int[100];
obj.setDataPointer(newData); // can be done
int** ptrToPtr = &obj.ptrData;
*ptrToPtr = &newData; // Cannot change ptr itself
class MyClass
{
public:
mutable int* ptrData;
public:
void setDataPointer(int* data) const
{
ptrData = data;
}
};
MyClass obj;
int* newData = new int[100];
obj.setDataPointer(newData); // error
When compiler sees a variable or object declared const, it is able to make certain performance optimizations based on the assumption that the state will not change.
领英推荐
// obj is declared const
const MyClass obj;
// Access member multiple times
obj.x;
obj.x;
obj.x;
Here, the compiler can optimize to cache the value of obj.x if it knows it won't change. It may even optimize away multiple reads to just read it once.
If we declare x as mutable;
class MyClass
{
mutable int x;
}
const MyClass obj;
obj.x;
obj.x; // may not be optimized
Now, compiler cannot make any assumptions about obj.x staying the same between two reads. It cannot cache or optimize away reads, because x could have been changed by another thread or mutable member function.
FAQ: Why static class members cannot be declared as mutable?
FAQ: Can we declare a function as mutable?
FAQ: Can we declare an object as mutable?
FAQ: Why there thread safety broken?
Let's understand using an example.
class MyClass
{
mutable int x;
...
};
const MyClass obj1;
// Thread 1
obj1.x = 10;
// Thread 2
obj1.x = 20; // Works as x is mutable!
FAQ: Why do any thread-safe guarantees on a const class get broken if it uses mutable?