const是“承诺不修改”的契约标记,位置决定修饰对象,用于变量、指针、成员函数、引用参数等场景,确保数据安全、提升可读性与优化机会;滥用const_cast会导致未定义行为。

const 在 C++ 里不是“只定义常量”的关键字,它本质是“承诺不修改”的契约标记——用错位置,编译器会直接报错;用对了,才能真正保护数据、提升可读性与优化机会。
const 变量声明:位置决定含义
声明 const 变量时,const 修饰的是它**左边紧邻的类型**(若左边无类型,则修饰右边)。这个规则直接影响指针和引用的行为:
-
int const x = 42;和const int x = 42;等价:x 是不可修改的整数 -
int* const ptr = &x;:ptr 指针本身不可变(不能指向别处),但 *ptr 可改 -
const int* ptr = &x;或int const* ptr = &x;:ptr 可变,但 *ptr 不可改(指向只读数据) -
const int* const ptr = &x;:指针和它指向的内容都不可变
实际开发中,尤其在函数参数传递指针/引用时,漏掉某一个 const 很容易导致编译失败或意外修改。
const 成员函数:隐式 this 指针被限定
在类成员函数声明末尾加 const,表示该函数**不会修改当前对象的任何非 mutable 成员**。编译器会把隐式的 this 指针变成 const T* const this,从而禁止对成员变量赋值、调用非 const 成员函数等操作:
class Data {
int value;
mutable int cache_hits; // mutable 是唯一例外:可在 const 函数中修改
public:
Data(int v) : value(v), cache_hits(0) {}
int get_value() const { // ✅ 正确:不修改 value
++cache_hits; // ✅ 允许:mutable 成员
return value;
}
void set_value(int v) { // ❌ 非 const 函数
value = v;
}};
常见错误:把本该是 const 的访问器(如 size()、at())漏写 const,导致无法在 const Data& d 上调用;或者在 const 函数里不小心调用了非 const 成员函数,编译器报错类似:error: passing 'const Data' as 'this' argument discards qualifiers。
const 引用参数:避免拷贝 + 保证安全
函数形参用 const T& 是 C++ 中最常用也最值得坚持的习惯之一:
- 传大对象(如
std::string、自定义类)时避免深拷贝开销 - 编译器禁止函数体内修改实参,从接口层面杜绝副作用
- 能接受字面量、临时对象、const 对象 —— 普通
T&不能绑定临时量
例如:void process(const std::vector 可以安全接收 process({1,2,3});而 void process(std::vector 就不行。
const_cast:极少需要,多数是设计缺陷的信号
const_cast 唯一合法用途是移除由“C 风格接口”强加的 const(比如调用老 C 库函数,它声称不改数据但没声明参数为 const)。除此之外,用 const_cast 修改原本声明为 const 的对象,属于未定义行为:
const int x = 10; int* p = const_cast(&x); *p = 20; // ❌ 未定义行为:x 是字面量级 const,可能存于只读段
真正需要修改的成员,应一开始就用 mutable 标记;需要可变接口,就提供 const/non-const 两个重载版本,而不是靠 const_cast 打补丁。
最容易被忽略的一点:const 正确性不是“加了就安全”,而是整个调用链都要一致——某个中间函数忘了加 const,就会让上游所有 const 保证失效。它像一层玻璃,一处裂缝,整面就失去作用。







