mutable修饰的成员变量可在const成员函数中修改,这是其最核心作用;它专用于缓存、引用计数、日志标记等逻辑上不改变对象状态但物理上需修改的内部字段,仅适用于非静态数据成员,不可与const/volatile共用,且不赋予对象整体可变性。

mutable修饰的成员变量能在const成员函数里被修改
这是mutable最核心的作用:绕过const语义对成员变量的写保护。比如缓存、引用计数、日志标记这类“逻辑上不改变对象状态,但物理上需要修改”的字段,就适合用mutable声明。
常见错误是把它当成“让const对象可变”的万能钥匙——其实它只解除对**该变量本身**的const限制,不影响其他成员,也不影响对象整体的const性(比如你仍不能在const函数里调用非const成员函数)。
-
mutable只能用于类的非静态数据成员,不能用于局部变量、全局变量或static成员 - 不能与
const、volatile同时修饰同一变量(语法报错) - 初始化必须在构造函数的成员初始化列表中完成,不能在类内直接赋值(C++11起允许类内默认初始化,如
mutable int cache = -1;)
典型使用场景:延迟计算与线程安全缓存
一个经典例子是实现带缓存的getHash():首次调用才真正计算,之后返回缓存值。这个缓存字段必须是mutable,否则无法在const成员函数中更新。
<pre class="brush:php;toolbar:false;">class Data {
mutable std::size_t hash_cache;
mutable bool hash_valid;
std::string content;
public:
Data(const std::string& s) : content(s), hash_cache(0), hash_valid(false) {}
std::size_t getHash() const {
if (!hash_valid) {
hash_cache = std::hash<:string>{}(content); // ✅ 允许修改mutable成员
hash_valid = true; // ✅ 同样允许
}
return hash_cache;
}
};</:string>
注意:这个例子在多线程下不安全——hash_valid
hash_cache的读写不是原子的。如果需要线程安全,得配合mutable std::mutex或mutable std::atomic_bool,而不是去掉mutable。
和const_cast对比:为什么不该用后者替代mutable
有人试图在const函数里用const_cast强转this指针来修改普通成员,这不仅丑陋,而且危险:
- 如果对象本身是const(比如
const Data d;),通过const_cast修改其成员会触发未定义行为(UB) -
mutable是语言明确支持的例外机制,编译器知道你在做什么,不会优化掉相关读写 - 调试时,
mutable字段在IDE里通常有特殊标识,而const_cast掩盖了意图
简言之:const_cast是“我强行改”,mutable是“我设计时就允许改”——语义完全不同。
容易忽略的细节:mutable对拷贝/移动操作没特殊待遇
mutable不改变任何特殊成员函数的行为。拷贝构造函数、移动构造函数、赋值运算符照常处理这些变量——它们不会自动跳过、也不会被特别对待。
比如你有一个mutable std::vector<int> temp_buffer;</int>,在拷贝对象时,这个buffer照样会被拷贝(除非你显式在拷贝构造函数里重置它)。它只是“可变”,不是“临时”或“不参与对象语义”。
真正容易被忽略的是:当类作为std::map的key或放入std::set时,如果比较逻辑依赖于mutable字段,结果可能违反容器的有序性要求——因为const成员函数可能悄悄改变了key的逻辑值,而容器并不知情。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











