C++ 笔记:const 正确性与 mutable:不可变性的设计
发布于:
前言
const 正确性是 C++ 编程的重要原则,它通过类型系统保证对象的不变性,提高代码的安全性和可维护性。理解 const 的语义、使用场景和 mutable 关键字,是写出健壮 C++ 代码的关键。本文将从 const 语义、使用规则、mutable 应用等多个维度深入解析 const 正确性,帮助读者全面理解这一重要概念。
1. const 的语义
1.1 const 的基本含义
const 表示”不可修改”:
const int x = 42;
x = 10; // 错误:不能修改 const 对象
const int* ptr = &x; // 指向 const 的指针
*ptr = 10; // 错误:不能通过 ptr 修改
1.2 const 的位置
const int* p1; // 指向 const int 的指针
int const* p2; // 同上,等价写法
int* const p3; // const 指针,指向 int
const int* const p4; // const 指针,指向 const int
2. const 成员函数
2.1 const 成员函数的含义
class MyClass {
private:
int value_;
public:
int get() const { // const 成员函数
return value_; // 不能修改成员变量
}
void set(int v) { // 非 const 成员函数
value_ = v; // 可以修改成员变量
}
};
2.2 const 对象只能调用 const 成员函数
const MyClass obj;
int x = obj.get(); // OK:调用 const 成员函数
obj.set(10); // 错误:不能调用非 const 成员函数
3. const 正确性的重要性
3.1 防止意外修改
void process(const std::vector<int>& vec) {
// vec 是 const 引用,不能修改
// 保证函数不会意外修改参数
for (int x : vec) {
// 处理
}
}
3.2 提高代码可读性
// const 明确表示函数不会修改对象
int get_value() const;
// 非 const 表示函数可能修改对象
void set_value(int v);
4. mutable 关键字
4.1 mutable 的用途
mutable 允许在 const 成员函数中修改成员变量:
class Cache {
private:
mutable int cache_value_;
mutable bool cache_valid_;
int compute_expensive() const;
public:
int get_value() const {
if (!cache_valid_) {
cache_value_ = compute_expensive(); // mutable 允许修改
cache_valid_ = true;
}
return cache_value_;
}
};
4.2 mutable 的应用场景
// 1. 缓存
class ExpensiveComputation {
mutable std::optional<int> cache_;
public:
int compute() const {
if (!cache_) {
cache_ = do_computation();
}
return *cache_;
}
};
// 2. 互斥锁
class ThreadSafeCounter {
mutable std::mutex mtx_;
int count_;
public:
int get() const {
std::lock_guard<std::mutex> lock(mtx_); // mutable 允许锁定
return count_;
}
};
5. const 与指针
5.1 指向 const 的指针
const int* ptr; // 指向 const int
int x = 42;
ptr = &x;
// *ptr = 10; // 错误:不能通过 ptr 修改
5.2 const 指针
int* const ptr = &x; // const 指针
// ptr = &y; // 错误:不能修改指针本身
*ptr = 10; // OK:可以修改指向的对象
5.3 const 引用
const int& ref = x; // const 引用
// ref = 10; // 错误:不能通过 ref 修改
6. const 与函数参数
6.1 值传递
void func(int x) { // 拷贝,不需要 const
// x 是局部变量,修改不影响原对象
}
6.2 引用传递
void func(const int& x) { // const 引用
// 不能修改 x,避免意外修改原对象
}
void modify(int& x) { // 非 const 引用
x = 10; // 明确表示会修改参数
}
6.3 指针传递
void func(const int* ptr) { // 指向 const 的指针
// 不能通过 ptr 修改指向的对象
}
void modify(int* ptr) { // 非 const 指针
*ptr = 10; // 明确表示会修改指向的对象
}
7. const 与返回值
7.1 返回 const 值
const int get_value() {
return 42;
}
// 通常不需要,因为返回值是临时对象
7.2 返回 const 引用
class Container {
private:
std::vector<int> data_;
public:
const int& get(size_t index) const {
return data_[index]; // 返回 const 引用,防止修改
}
};
8. const 正确性的实践
8.1 默认使用 const
// 好的实践:默认使用 const
void process(const std::vector<int>& vec) const;
// 只在需要修改时才使用非 const
void modify(std::vector<int>& vec);
8.2 const 成员函数的重载
class Array {
private:
int* data_;
public:
int& operator[](size_t index) {
return data_[index];
}
const int& operator[](size_t index) const {
return data_[index];
}
};
9. 常见错误
9.1 忘记 const
class MyClass {
public:
int get() { // 应该是 const
return value_;
}
};
const MyClass obj;
obj.get(); // 错误:不能调用非 const 成员函数
9.2 过度使用 mutable
// 不好:过度使用 mutable
class Bad {
mutable int value_; // 不应该用 mutable
public:
int get() const {
return value_;
}
};
10. 小结
const 正确性通过类型系统保证对象的不变性,提高代码的安全性和可维护性。
核心要点:
- const 表示不可修改
- const 成员函数不能修改成员变量
- const 对象只能调用 const 成员函数
- mutable 允许在 const 函数中修改特定成员
- 默认使用 const,只在需要修改时使用非 const
掌握 const 正确性,可以写出更安全、更健壮的 C++ 代码。