Last updated:2026-10-12
C++ mutable Keyword¶
A Deep Dive into the mutable Keyword in C++¶
In C++, the mutable keyword is often regarded as a tool for "piercing through" the const restriction. In some cases, although we want to impose const protection on an object, we still need to modify some of its data members. This article explores in depth the use cases of mutable and the design philosophy behind it, and discusses how it solves specific programming needs in C++.
1. The Basic Use of the mutable Keyword¶
We know that when a member function is qualified with const, that member function guarantees it will not modify the object's state. In actual programming, however, we sometimes want to modify a data member while still marking the member function const. This is what the mutable keyword is for:
class Foo
{
private:
mutable bool done_;
public:
void doSomething() const {
// 在 const 成员函数中修改 mutable 成员
done_ = true;
}
};
In the example above, doSomething() is declared const, indicating that it does not change the object's state. done_, however, is marked mutable, which means we can still modify done_ even inside a const method. This design lets us manage the data that does need modification while keeping the function's interface semantics unchanged.
2. Logical Constness vs. Bitwise Constness¶
Constness in C++ falls into two categories: logical constness and bitwise constness. Logical constness means that the object's state appears unchanged from the outside, while bitwise constness means that the object's bits in memory remain unchanged. The mutable keyword allows us to define logical constness: even if some of the object's internal data changes, the object's state shows no observable change in a logical sense.
For example, in a thread-safe class we might use boost::mutex to protect data access. To acquire the lock inside a const method, we can declare the mutex as mutable:
class ThreadSafeClass {
private:
mutable std::mutex mtx_;
int data_;
public:
int getData() const {
std::lock_guard<std::mutex> lock(mtx_);
return data_;
}
};
In the example above, although the getData method is declared const, we need the lock to keep data access thread-safe. We therefore declare mtx_ as mutable, to allow modifying it inside a const method. In this case, we say the class's logical state has not changed; the modification exists only to ensure thread safety.
3. mutable in Lambda Expressions¶
Since C++11, mutable can also be used in lambda expressions to allow the modification of variables captured by value. By default, variables captured by value in a lambda are immutable. If you need to modify a captured variable inside the lambda, you can use mutable:
int x = 0;
auto f1 = [=]() mutable { x = 42; }; // OK: 可以修改捕获的 x
auto f2 = [=]() { x = 42; }; // Error: 按值捕获的变量不能被修改
In this case, mutable allows us to modify the captured variables inside the function body without affecting the values of the outer variables.
4. Avoiding const_cast¶
Without the mutable keyword, we might need const_cast to handle these special cases. const_cast can strip away an object's constness, but it has drawbacks: const_cast can remove const protection entirely, letting us make arbitrary modifications to and method calls on the object, which degrades the code's readability and safety.
By comparison, the mutable keyword provides a finer-grained form of control. With mutable, we can set up "exceptions" on specific data members, allowing modification inside const methods without stripping the constness from the whole object. mutable therefore handles these special cases more safely.
5. The Design Philosophy of Using mutable¶
The design philosophy of the mutable keyword lies in preserving the interface's logical constness. In most cases, we want to write const-correct code, which means the object's state does not change unless explicitly modified. mutable allows us to make concessions in some internal implementation details — such as caching, reference counting, or debug information — without breaking the consistency of this interface design.
When designing an interface, we should be clear about when and why an object's state needs to be modified. The mutable keyword keeps the code unchanged at the logical level while still providing the ability to modify specific data members. This requires the designer to think it through carefully, making sure the use of mutable does not destroy the notion of the object's constness, and to use it only when it is genuinely needed.
6. References¶
Related Topics¶
- C++ Pure Virtual Functions and Abstract Classes | C++那些事
- C++ assert | C++那些事
- C++ Bit Fields | C++那些事
- Implementing C++ Polymorphism in C | C++那些事
- C++ const Constants and Qualifiers | C++那些事
- The Complete C++ const Family | C++那些事
- C++ Dereference Operator * | C++那些事
- C++ Initialization and Assignment | C++那些事
- Ways to Return Multiple Values in C++ | C++那些事
- C++ restrict and Compiler Optimization | C++那些事