const变量必须定义时初始化,否则编译报错;初始化后任何修改均为未定义行为;类内静态const需在.cpp中再次定义;宏常量易因缺乏类型检查和括号导致错误;constexpr比const更严格保证编译期求值。

const 变量怎么写才真正不可修改
用 const 定义常量,不是加个关键字就完事——它必须在定义时初始化,否则编译直接报错:error: uninitialized const。而且一旦初始化,后续任何赋值或取地址后修改(哪怕用 const_cast)都属于未定义行为,不是“改不了”,而是“改了结果不可预测”。
- 推荐写法:
const int MAX_SIZE = 1024;(带初始化、类型明确) - 避免写法:
const int MAX_SIZE;(未初始化,编译失败) - 类内静态常量需额外处理:
static const double PI = 3.14159;,若要在其他文件中取地址,还得在 .cpp 里再定义一次const double MyClass::PI;
#define 宏常量为什么容易出错
#define 是纯文本替换,不经过类型检查,也不进作用域。比如 #define BUFFER_SIZE 1024 + 1,实际展开成 int a = BUFFER_SIZE * 2; 就变成 1024 + 1 * 2,结果是 1026 而不是预期的 2050。
- 必须加括号:
#define BUFFER_SIZE (1024 + 1) - 没有类型信息,调试器看不到值,IDE 无法跳转,重构时也搜不到引用
- 宏名污染全局命名空间,两个头文件里同名
#define会静默覆盖,连 warning 都不一定有
const 和 constexpr 在编译期常量上的关键差异
想让常量参与数组长度、模板参数这些需要编译期确定的场景,const 不一定够用——只有字面量初始化的 const 才算编译期常量;而 constexpr 强制要求编译期可求值,更可靠。
-
const int x = 42;✅ 可作数组大小:int arr[x]; -
const int y = rand();❌ 即使编译通过,也不能用于模板参数 -
constexpr int z = 42 + 1;✅ 明确保证编译期可用,且支持简单计算和函数
什么时候该用 const,什么时候该用 constexpr
日常变量级常量(如配置上限、状态码),优先用 const;涉及模板、数组维度、switch 分支值等必须编译期确定的,必须用 constexpr。C++17 起,constexpr 函数还能包含循环和局部变量,但别忘了:它仍要求所有路径在编译期可执行完毕。
立即学习“C++免费学习笔记(深入)”;
- 接口常量(头文件暴露):用
inline constexpr(C++17),避免 ODR 违规 - 类内初始化默认值:
static constexpr int DEFAULT_TIMEOUT = 5000; - 字符串字面量常量别用
const char*,改用constexpr std::string_view(C++20)或const char[]保类型安全
事情说清了就结束。最常被忽略的是:const 变量未必是编译期常量,而 constexpr 的函数体里调用了非 constexpr 函数,整条链就掉出编译期——这种错误往往到模板实例化时报错,位置离定义很远。










