
C++中的 mutable 详解
——为什么“不能改变”的东西,有时候可以改变?
同学们,我们前面学习了 const:
const 表示“不允许修改”。
比如:
const int x = 10;
x = 20; // 错误!
因为:
x 是常量
不能改变
那么问题来了:
如果一个东西整体不能改变,但是里面有一个小地方希望可以偷偷变化,怎么办?
这时候 C++ 给我们提供了一个特殊工具:
mutable(可变的)
一、先回忆 const 成员函数
在讲 mutable 之前,我们先复习一下:
类里面的 const 函数
例如:
class Student
{
public:
int age;
void show() const
{
cout << age;
}
};
注意:
void show() const
后面的 const
表示:
这个函数保证不会修改对象的数据。
例如:
class Student
{
public:
int age;
void change() const
{
age = 10; // 错误
}
};
为什么?
因为:
const函数
↓
不能修改成员变量
二、生活中的例子理解 mutable
假设:
你有一本:
《我的个人档案》
里面有:
姓名
年龄
生日
访问次数
例如:
class Book
{
public:
string name;
int price;
int visit;
};
现在有一个函数:
查看书的信息:
void show() const
{
cout << name;
}
我们希望:
用户每看一次书:
visit + 1
表示:
这本书被查看了多少次
于是:
void show() const
{
visit++;
cout << name;
}
编译器会说:
错误!
因为:
show() 是 const函数
不能修改任何成员变量
怎么办?
难道访问次数不能增加?
当然不是。
因为:
访问次数这个数据:
不是书本本身的信息。
书本:
名字
价格
作者
这些不能变。
但是:
访问次数
只是一个记录信息。
所以:
我们希望:
普通数据:
不能改
特殊数据:
允许改
这就是:
mutable 出场!
三、mutable的作用
一句话:
mutable 修饰的成员变量,可以在 const 成员函数中被修改。
格式:
mutable 数据类型 变量名;
例如:
class Book
{
public:
string name;
int price;
mutable int visit;
void show() const
{
visit++;
cout << name;
}
};
现在:
show()
里面:
visit++;
合法!
四、完整例子
#include<iostream>
using namespace std;
class Book
{
private:
string name;
int price;
mutable int count;
public:
Book(string n,int p)
{
name=n;
price=p;
count=0;
}
void show() const
{
count++;
cout<<"书名:"<<name<<endl;
cout<<"价格:"<<price<<endl;
cout<<"查看次数:"<<count<<endl;
}
};
int main()
{
Book b("C++入门",50);
b.show();
b.show();
b.show();
return 0;
}
输出:
书名:C++入门
价格:50
查看次数:1
书名:C++入门
价格:50
查看次数:2
书名:C++入门
价格:50
查看次数:3
五、为什么C++允许这样设计?
我们思考:
const的本质是什么?
const告诉别人:
我承诺,不修改这个对象的重要内容。
但是:
有一些变量:
虽然会变化,
但是:
它不是对象真正的数据。
例如:
例1:访问次数
网站:
用户名
密码
等级
访问次数
访问次数变化:
但是用户名没有变化。
例2:缓存数据
比如:
计算:
1+2+3+…+100000
很慢。
第一次:
计算:
结果=5000050000
保存起来。
第二次:
直接返回。
这个保存结果:
叫:
缓存(cache)
缓存可以改变:
但是:
对象逻辑没有改变。
所以:
mutable
非常适合。
六、mutable和普通变量的区别
| 普通成员变量 | ❌不能 |
| mutable成员变量 | ✅可以 |
例如:
class A
{
int x;
mutable int y;
void test() const
{
x++; //错误
y++; //正确
}
};
七、mutable 和 const 对象
看一个更特殊情况:
class Student
{
public:
mutable int score;
};
int main()
{
const Student s;
s.score=100;
}
居然可以!
为什么?
因为:
score是mutable
所以:
即使对象是const:
它仍然允许修改。
八、mutable的底层理解
同学们可以这样理解:
普通变量:
对象
|
+— age
|
+— name
const对象:
全部锁住
但是:
mutable:
对象
|
+— age 🔒
|
+— name 🔒
|
+— cache 🔓
给某些成员变量开一个“小后门”。
九、什么时候使用mutable?
在实际C++开发中,主要有三个用途:
1. 统计信息
例如:
mutable int count;
记录:
-
调用次数
-
点击次数
-
访问次数
2. 缓存结果
例如:
mutable double result;
保存:
计算结果。
3. 多线程中的锁
高级C++中:
经常看到:
mutable mutex m;
因为:
即使函数是const:
也可能需要加锁。
十、信奥竞赛中需要掌握吗?
对于:
GESP/CSP-J阶段:
通常:
不考 mutable 的复杂应用。
但是:
理解它有两个价值:
帮助理解 const
为以后学习C++ STL源码打基础
例如:
以后看:
string
vector
map
源码时:
会看到:
mutable
十一、一句话总结
记住一句口诀:
const 是“大门锁”,禁止修改;
mutable 是“小抽屉”,允许特殊修改。
或者:
const对象:
大部分不能改变
mutable变量:
特殊变量可以改变
最后的类比:
爸爸说:
“我的书房不能乱动。”
这是:
const
但是:
爸爸允许:
“墙上的日历可以每天更新。”
这个日历:
就是:
mutable
所以:
mutable不是破坏const,而是告诉编译器:
“这个变化不属于对象本质变化,只是额外记录信息。”
对于初学C++的小学生,可以把 mutable 放在学习路线:
类
↓
this指针
↓
const成员函数
↓
mutable
↓
拷贝构造
↓
运算符重载
这是面向对象理解中的一个重要小知识点。





