原生数组越界访问是未定义行为,不抛异常且try/catch无法捕获;只有std::vector::at()等显式检查函数才抛std::out_of_range供catch捕获。

原生数组 [] 越界访问不会抛异常,try/catch 捕不到
不能。C++ 原生数组(如 int arr[10])使用 arr[i] 访问时,编译器不做边界检查,越界是未定义行为(UB),既不抛 std::out_of_range,也不触发任何标准异常。程序可能读到垃圾值、覆盖其他变量、崩溃,或者看似“正常”运行——但结果完全不可预测。
常见错误现象:
- 调试时值随机变化,Release 模式下行为突变
- 用 AddressSanitizer 检测到 heap-buffer-overflow 或 stack-buffer-overflow
-
try/catch(...)完全无反应,程序仍直接终止或静默出错
std::vector::at() 和 std::string::at() 才真正抛异常
只有显式调用带检查的访问函数,才会触发可捕获的异常。它们内部检测越界后会 throw std::out_of_range,这才是 catch 能起作用的场景。
使用示例:
std::vector<int> v = {1, 2, 3};
try {
int x = v.at(10); // 抛 std::out_of_range
} catch (const std::out_of_range& e) {
std::cout = this->size() (which is 3)"
}</int>
注意点:
-
v[10](方括号)依然不抛异常,和原生数组一样危险 - 必须
#include <stdexcept></stdexcept>才能捕获std::out_of_range - 性能上
at()比[]多一次比较,仅在调试或关键校验处启用
为什么 C++ 不给原生数组加边界检查
这是语言设计层面的取舍:零成本抽象原则。C++ 默认不为运行时安全牺牲性能,把检查权交给程序员或更高层容器。
实际影响:
- 静态数组(
int a[5])和动态分配数组(new int[5])都无内置检查 - 即使开启
-fsanitize=address,也只是检测并报告,不是抛标准异常,catch依然无效 - 跨平台代码中,依赖越界崩溃来定位 bug 是不可靠的;更应依赖
vector::at()、迭代器范围检查或静态分析工具
替代方案:不用原生数组,改用带检查的容器
真要捕获越界,唯一可靠路径是避开原生数组,转向标准库容器并主动调用 at()。
可行做法:
- 用
std::vector替代new int[n],用vec.at(i)替代ptr[i] - 用
std::array替代栈上 C 风格数组,它也提供at()成员函数 - 若必须用指针(如对接 C API),封装一层带断言或日志的访问函数,而非指望
try/catch
最易被忽略的一点:很多人以为开了编译器警告(如 -Warray-bounds)就能捕获越界,其实那只是编译期提示,对运行时越界毫无作用。真正的防护只能靠容器 + at() + 显式 catch 组合。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











