const成员必须在初始化列表中初始化,不能在构造函数体内赋值;mutable仅允许在const函数中修改,用于缓存等不影响逻辑不可变性的场景;需显式删除拷贝/移动赋值以确保真正不可变。

构造函数里必须初始化所有const成员
如果类里有const数据成员(比如const std::string name_),它们**不能在构造函数体里赋值**,只能在成员初始化列表中完成。否则编译直接报错:error: uninitialized const member。
这是因为const对象一旦创建就不可修改,C++ 要求它从诞生那一刻起就有确定值。
实操建议:
- 所有
const成员、引用成员、没有默认构造函数的类类型成员,都必须出现在初始化列表里 - 初始化顺序严格按类定义中声明的顺序,跟初始化列表里写的顺序无关——写错顺序可能引发未定义行为(比如用后面才初始化的成员去初始化前面的)
- 避免在初始化列表里调用可能抛异常的函数;若必须调用,考虑用
std::optional或工厂函数封装异常处理逻辑
mutable不是用来绕过“只读”的,而是给线程安全/缓存留后门
有人误以为加个mutable就能让const成员“可写”,从而实现“伪只读”。其实mutable只允许在const成员函数里修改该变量,它不破坏逻辑上的不可变性设计,只是放宽了物理约束。
立即学习“C++免费学习笔记(深入)”;
典型用途是缓存计算结果、引用计数、日志标记等不影响对外语义的状态:
class Point {
public:
double distance_from_origin() const {
if (!cached_distance_) {
cached_distance_ = std::sqrt(x_*x_ + y_*y_);
}
return *cached_distance_;
}
private:
const double x_, y_;
mutable std::optional<double> cached_distance_; // 合理使用 mutable
};注意:mutable不能用于const指针所指向的内容(比如const int* const p中的*p),也不能用于const容器里的元素。
真正不可变 ≠ 所有成员都加const
把每个字段都标成const看似保险,但实际会带来维护成本和灵活性问题。例如:
-
std::vector<int></int>不能是const,否则无法用push_back初始化(哪怕只在构造时) - 自定义类型若没提供合适的
const构造路径,会导致初始化失败 - 移动语义失效:
const右值无法被移动,可能触发不必要的拷贝
更务实的做法是:对外接口全部const,内部用private + const + 初始化列表 + 删除operator=来封死修改入口:
class ImmutableConfig {
public:
ImmutableConfig(const std::string& host, int port)
: host_(host), port_(port) {}
<pre class="brush:php;toolbar:false;">const std::string& host() const { return host_; }
int port() const { return port_; }
ImmutableConfig(const ImmutableConfig&) = default;
ImmutableConfig& operator=(const ImmutableConfig&) = delete; // 禁止赋值private: const std::string host; const int port; };
别忘了禁用移动赋值和拷贝赋值
即使所有成员都是const,只要没显式删除operator=,编译器仍会生成默认的拷贝/移动赋值函数——而这些函数试图给const成员重新赋值,导致编译失败。但失败时机晚(在使用点而非定义点),容易让人困惑。
更糟的是:如果类里混有非const成员,赋值操作可能静默成功,彻底破坏不可变性。
所以务必显式删除:
ImmutableConfig& operator=(const ImmutableConfig&) = delete;ImmutableConfig& operator=(ImmutableConfig&&) = delete;
如果真需要“创建新实例”,应提供工厂函数或with_xxx()风格的返回新对象的方法,而不是试图修改旧对象。
最易被忽略的一点:继承体系下,基类的=delete不会自动传导到派生类;若派生类没显式删除,编译器会生成自己的赋值函数,可能绕过基类的保护逻辑。


















