应将 const 放在数组类型之后定义不可修改的数组对象,如 const int arr[3] = {1,2,3};推荐使用 const std::array 替代 c 风格数组,其支持拷贝、constexpr 初始化和范围 for;运行时大小需用 const std::vector 引用或 std::span 实现只读视图。

用 const 修饰数组变量名,不是元素类型
很多人误写成 const int arr[] = {1,2,3};,以为这样就“常量化”了数组——其实这只是让每个元素变成 const int,而数组本身仍可被整体赋值(比如用指针重绑定),且无法通过 sizeof 正确获取长度。真正要定义“不可修改的数组对象”,得把 const 放在数组类型之后:int const arr[] = {1,2,3}; 或更清晰地写成 const int arr[3] = {1,2,3};。关键点是:数组名 arr 是 const 对象,不能被赋值、不能取地址后改写内容(编译器会拦住),sizeof(arr) 也能正常返回总字节数。
推荐用 std::array 替代 C 风格数组
C++11 起,std::array 是更安全、更实用的选择。它本质是带大小的栈上容器,支持拷贝、constexpr 初始化、范围 for,且不会隐式退化为指针。const std::array<int> arr = {1,2,3};</int> 这样定义后,arr[0] = 5; 直接编译失败,arr.size() 返回 3,sizeof(arr) 等于 3 * sizeof(int)。注意两点:
- 模板参数里的大小必须是编译期常量,不能是变量
- 初始化列表元素个数必须严格匹配,否则 GCC/Clang 会报错(不是警告)
需要运行时确定大小?只能用 std::vector + const 引用
如果数组长度直到运行时才知(比如读配置文件),C 风格数组和 std::array 都无能为力。这时常见做法是:用 std::vector 构造好数据,再用 const 引用或指针封住接口:const std::vector<int> data = load_from_file();</int>。这样调用方无法修改内容,但要注意:
-
data本身是 const 对象,不能调用push_back等非 const 成员函数 - 底层内存仍是可写的(若原始 vector 非 const),所以这不是绝对安全的“只读视图”
- 真要隔离修改,得用
std::span<const int></const>(C++20)或自定义只读包装类
宏定义或 constexpr 数组?看场景选
如果数组内容完全编译期可知,且需用于模板参数或 switch case,优先用 constexpr:constexpr int kValues[] = {10, 20, 30};。它比 #define 安全(有类型、作用域、调试信息),也比普通 const 更严格(能参与常量表达式)。但注意:
-
constexpr数组要求所有元素初始化器都是常量表达式 - 若数组较大,可能触发某些编译器的 constexpr 展开深度限制
- VS2019 及更早版本对
constexpr数组的std::get支持不完整,建议升级或换用std::array
真正难处理的是“外部输入 → 编译期常量数组”这种需求,比如想把 JSON 配置在编译时转成 constexpr 数组——这已超出语言本身能力,得靠构建脚本或 C++20 的反射提案(尚未落地)。实际项目中,多数时候老老实实用 const std::array 就够了,别为了“绝对 const”过度设计。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











