vector::at() 会抛出 std::out_of_range 异常,operator[] 不检查越界且行为未定义;at() 是标准强制边界检查,operator[] 始终零开销、无编译选项可启用检查。
![c++ vector at和[]区别 c++数组越界检查机制详解【调试】](https://img.php.cn/upload/article/001/431/639/176983508534317.jpg)
vector::at() 会抛异常,operator[] 不检查越界
这是最核心的区别:调用 vec.at(i) 时,如果 i 超出 [0, vec.size()) 范围,会立即抛出 std::out_of_range 异常;而 vec[i] 完全不检查,行为未定义(可能崩溃、读到垃圾值、静默错误)。调试时若看到程序在访问 vector 元素后莫名崩溃或数据错乱,优先怀疑 [] 越界。
release 模式下 [] 不做任何边界检查
operator[] 的设计目标是零开销——编译器不会插入任何检查逻辑,无论 debug 还是 release。即使你启用了 -D_GLIBCXX_DEBUG(GCC 的 debug mode),它也只影响迭代器和部分容器操作,[] 依然不查。只有 at() 是标准强制要求检查的,且在所有标准库实现中都生效。
- 想靠编译选项让
[]自动检查?做不到 - 想用
assert(i 手动防护?仅在NDEBUG未定义时有效,release 下直接消失 - 调试阶段可临时把
[]替成at()快速暴露问题
数组原生指针没有越界检查机制
C++ 原生数组(如 int arr[10])和指向堆内存的指针(如 new int[10])完全不提供任何运行时边界信息。arr[15] 或 ptr[-3] 编译通过、运行可能不报错,但属于未定义行为。工具链层面:
-
AddressSanitizer (-fsanitize=address)可捕获这类越界读写,强烈建议开发期启用 -
UndefinedBehaviorSanitizer (-fsanitize=undefined)对某些越界访问也有提示能力 - GDB 中无法单靠
print arr[20]判断是否越界——它只会尝试读内存,不管合法与否
at() 的异常成本和适用场景
at() 每次调用都有分支判断和潜在异常开销,不适合高频循环内使用(比如图像像素遍历)。但它适合以下情况:
立即学习“C++免费学习笔记(深入)”;
- 用户输入索引(如命令行参数、配置文件读取)
- 算法中索引来源不可信(如解析外部数据结构)
- 调试期快速定位越界源头,比加一堆
assert更直接
注意:at() 抛的是 std::out_of_range,不是 std::range_error,捕获时别写错类型。另外,空 vector 调用 at(0) 同样抛异常——这点和 front() 不同,后者对空容器是未定义行为。
越界问题最难缠的不是崩溃,而是“看起来正常却改写了别的变量”。用 at() 把隐性错误变成显性异常,比靠运气调试省太多时间。










