c++数组越界默认不检查,越界读写导致未定义行为;应优先用std::vector::at()、地址消毒器、std::span及带assert的包装器防范。

数组越界在 C++ 里根本不会自动报错
编译器和运行时默认不检查 operator[] 或指针算术的边界。越界读可能拿到垃圾值,越界写大概率破坏相邻变量、栈帧甚至导致段错误——但不是“一定立刻崩溃”,这正是最危险的地方。
- 用
std::vector::at()替代operator[],它会在调试/非优化构建中抛出std::out_of_range - 启用编译器地址消毒器:
g++ -fsanitize=address或clang++ -fsanitize=address,能捕获绝大多数越界访问(含堆、栈、全局) - 静态分析工具如
clang++ -Weverything或cppcheck可发现部分明显越界(比如常量索引超声明长度)
std::array 和 std::vector 的边界行为差异
std::array 是栈上固定大小容器,operator[] 不检查;std::vector 同理,但多了 at() 这个带检查的接口。二者都不提供“自动扩容”或“安全截断”逻辑。
-
std::array<int> a; a[10] = 42;</int>—— 未定义行为,无警告,不抛异常 -
std::vector<int> v(5); v.at(10) = 42;</int>—— 抛std::out_of_range(但v[10]依然不检查) -
v.data()[10]等价于裸指针访问,完全绕过vector的任何保护
用 span 替代裸指针和原始数组参数
函数接收原始数组或指针时,长度信息极易丢失或误传。C++20 引入的 std::span 把数据+长度绑在一起,且支持编译期长度推导和运行时边界检查(配合 sanitizer)。
- 避免写
void process(int* arr, size_t len),改用void process(std::span<const int> arr)</const> -
std::span构造时若传入空指针+非零长度,行为未定义;但用std::span(arr, len)比手动传两个参数更难出错 - 注意:MSVC 2019 16.8+ / GCC 10+ / Clang 9+ 才有完整支持;旧项目可用
gsl::span(Guideline Support Library)作兼容
自定义数组类加 assert 检查的实用底线
如果无法升级到 C++20 或引入第三方库,自己封装一个轻量级带断言的数组包装器,比全程靠人工 review 更可靠。
立即学习“C++免费学习笔记(深入)”;
- 只在
DEBUG模式下检查,不影响发布性能:assert(idx - 不要重载
operator[]返回引用后允许赋值——必须同时覆盖 const/non-const 版本,否则易漏检查 - 避免模板全特化陷阱:对
bool特化时,std::vector<bool></bool>是位压缩实现,data()不可用,span也不适用
越界问题从来不是“会不会发生”,而是“什么时候暴露”。靠人盯代码不如让工具在构建或运行时拦住它,尤其当数组索引来自用户输入、文件解析或网络包时,少一次 assert 就多一分不可控风险。










