mutable修饰的成员变量可在const成员函数中修改,用于缓存、引用计数等不影响对象逻辑状态的内部可变数据;它仅适用于非静态数据成员,不传导至所指/所含对象,且无未定义行为风险。

mutable 修饰的成员变量可以在 const 成员函数里修改
当一个成员函数被声明为 const,编译器默认禁止它修改任何成员变量——但 mutable 是唯一例外。它告诉编译器:“这个变量逻辑上不改变对象状态,允许在 const 函数中写入”。典型用途是缓存、引用计数、日志标记等不影响对外可见行为的内部状态。
常见错误现象:error: assignment of member 'cache_valid' in read-only object,就是因为忘了加 mutable 却在 const 函数里赋值。
-
mutable只能用于类的非静态数据成员,不能用于局部变量、全局变量或 static 成员 - 不能与
static、const同时修饰同一成员(mutable const int x;是非法的) - 即使变量本身是
const类型(如mutable const std::string* ptr;),mutable修饰的是“指针可变”,不是“所指内容可变”
const 成员函数里修改 mutable 成员的典型场景
最常见的是惰性计算和线程安全缓存。比如一个 get_data() 是 const 的,但内部想缓存上次结果避免重复构造:
class DataWrapper {
mutable std::string cached_data;
mutable bool cache_valid = false;
public:
std::string get_data() const {
if (!cache_valid) {
cached_data = expensive_computation(); // ✅ 允许:cached_data 是 mutable
cache_valid = true; // ✅ 允许:cache_valid 是 mutable
}
return cached_data;
}
};注意:如果 expensive_computation() 不是线程安全的,这种写法在多线程下会出问题——mutable 不提供同步保障,只是绕过 const 限制。
立即学习“C++免费学习笔记(深入)”;
- 别用
mutable去“偷改”业务上真正影响对象语义的字段(比如把mutable int age;放在 Person 类里,在const print_info()里悄悄改年龄) - 调试时容易忽略
mutable成员的变化,建议在注释里明确说明其作用(例如// mutable: 仅用于内部缓存,不改变逻辑状态)
mutable 和 const_cast 的关键区别
有人试图用 const_cast 在 const 函数里强转掉 this 的 const 性来修改普通成员,这是危险且未定义行为(UB)——除非原对象本身是非 const 的。而 mutable 是语言层面对特定成员的合法授权,无 UB 风险。
-
const_cast:依赖调用者传入的是非 const 对象,否则 UB(this)->cache_valid = true; -
mutable bool cache_valid;+ 直接赋值:始终合法,无论对象如何被调用 - 编译器可能对
mutable成员做不同优化(例如不参与 const 对象的只读段放置),但一般不用手动干预
容易被忽略的细节:mutable 不影响 const 引用/指针的解引用
如果你有一个 mutable std::unique_ptr,在 const 函数里可以调用 ptr.reset()(因为 reset() 是非 const 成员函数),但不能通过 *ptr 或 ptr->foo() 修改 T 的内容——除非 T 本身的成员也是 mutable 或者 foo() 是 const 成员函数。
也就是说:mutable 只放宽“该成员变量自身是否可被赋值/调用非 const 成员函数”的限制,不传导到它所指向/包含的对象内部。
实际写的时候,最容易漏掉的是跨层 mutable —— 比如缓存里存了一个 std::vector,你想在 const 函数里 push_back,那就得确保 vector 本身是 mutable,而 vector 内部的元素增删是它自己的接口约束,跟外层 mutable 无关。








