const变量赋值仅发生在初始化阶段,编译器将其视为编译期常量并内联优化;运行时赋值非法,const成员必须用初始化列表赋值,类内默认初始化仅适用于默认构造函数。

const变量的赋值发生在初始化阶段,不是运行时可重复操作
编译器把 const 变量当作“编译期常量”来处理(尤其当它有字面量初始化时),其值被内联进所有使用位置,根本不会在内存中保留可修改的左值。比如:
const int x = 42; int arr[x]; // 合法:x 是常量表达式,用于变长数组(C++不支持,但说明其编译期地位)
即使像 const int y = get_value(); 这样运行时初始化的,y 也仅允许一次绑定——之后任何 y = 100; 都会被编译器拦截,报错 assignment of read-only variable 'y'。
常见错误现象
立即学习“C++免费学习笔记(深入)”;
- 在构造函数体里给
const成员赋值:num = val;→ 编译失败,提示assignment of read-only member 'Test::num' - 声明时没初始化:
const int a;→ 编译失败,提示uninitialized const 'a' - 用指针绕过 const 限制(如
const int a = 0; int* p = const_cast<int*>(&a); *p = 97;)→ 行为未定义,可能看似成功但破坏了优化假设,或在启用-O2后输出仍是旧值
为什么这样做
不是为了“阻止程序员”,而是为了让编译器能安全地做两件事:一是常量折叠(2 * PI 直接替换成数值),二是跨函数内联与寄存器分配(知道该值永不变,就不用反复从内存 reload)。一旦允许运行时赋值,这些优化就不可靠了。
const 成员变量必须用初始化列表
类内 const 成员没有默认构造行为,对象内存布局在进入构造函数体前就已固定。此时唯一合法的赋值时机,是冒号后的初始化列表:
class Widget {
const int id;
public:
Widget(int i) : id(i) {} // ✅ 唯一正确写法
// Widget(int i) { id = i; } // ❌ 编译错误
};
如果漏掉初始化列表,哪怕只漏一个 const 成员,整个构造函数就无法通过编译。
C++11 类内默认初始化只是语法糖
写成 const int id = 42; 看似宽松,但它只对**默认构造函数**生效;只要定义了带参构造函数,且没在初始化列表中显式覆盖该成员,编译器仍会报错。它本质是让编译器自动把 = 42 插入到默认构造函数的初始化列表里,不是放宽语义。
真正容易被忽略的点:const 的约束力来自编译器检查 + ABI 约定,不是内存保护。你永远可以通过 const_cast 或越界写内存强行改——但那不是“const 失效”,而是你主动跳出了语言契约,后果自负。


















