const允许运行时初始化但必须定义时一次性赋值,constexpr则严格要求编译期常量;const成员变量须用构造函数初始化列表,不可在函数体内赋值。

可以,但仅限于 const,不能用于 constexpr。
const 变量允许运行时输入初始化
只要在定义时完成一次赋值,const 就接受任何合法的右值,包括用户输入、函数返回值、甚至随机数。编译器不关心这个值何时确定,只保证它之后不可修改。
-
std::cin >>读入后立即用于const初始化是完全合法的 - 必须在定义语句中完成初始化,不能先声明再赋值(
const int x; x = 5;会编译失败) - 常见错误:把输入和初始化拆成两步,误以为“先有变量再赋值”可行
#include <iostream>
int main() {
int tmp;
std::cin >> tmp;
const int user_val = tmp; // ✅ 合法:运行时确定,但只赋一次
// const int bad; bad = tmp; // ❌ 编译错误:未初始化 + 二次赋值
}
constexpr 绝对不允许运行时输入
constexpr 要求整个表达式在编译期可求值,而 std::cin、std::rand()、函数调用(除非是 constexpr 函数)等都属于运行期行为,直接导致编译失败。
- 哪怕只是“看起来像常量”,比如
const int x = getUserInput(); constexpr int y = x;也不行 ——x是运行时常量,不能降级为编译时常量 - 数组大小、模板非类型参数、
switchcase 标签等上下文强制要求编译期常量,此时只能用字面量或constexpr表达式
int getUserInput() { int x; std::cin >> x; return x; }
// constexpr int size = getUserInput(); // ❌ 编译错误:不是常量表达式
// int arr[size]; // ❌ 即使 size 是 const,也不能用于变长数组(C++标准不支持)
constexpr int size = 10; // ✅ 唯一安全方式
int arr[size]; // ✅ 合法:编译期可知大小
const 成员变量必须用初始化列表,不能靠运行时赋值
类内 const 成员不能在构造函数体内赋值,哪怕你刚从 std::cin 读到值也不行 —— 它们必须在对象创建时就通过初始化列表“一次性定终身”。
立即学习“C++免费学习笔记(深入)”;
- 错误写法:
MyClass(int v) { const_val = v; }→ 编译失败 - 正确写法:
MyClass(int v) : const_val(v) {} - 如果要基于输入初始化,得先把输入读到临时变量,再传进构造函数
struct Config {
const int port;
Config(int p) : port(p) {} // ✅ 必须初始化列表
};
int main() {
int input_port;
std::cin >> input_port;
Config cfg(input_port); // ✅ 运行时输入 → 传参 → 初始化列表
}
真正容易被忽略的是:const 的“运行时”属性不等于“可延迟初始化”。它仍严格要求定义即初始化,只是这个“定义点”可以落在运行期流程中 —— 比如 main 函数里、某个函数作用域开头,甚至 lambda 内。一旦错过那个定义语句,就再没机会了。


















