vector::at() 总是边界检查并抛出 std::out_of_range 异常,operator[] 从不检查、越界行为未定义;调试推荐用 at(),性能关键处确保安全后可用 [];ASan 是跨平台最可靠的越界检测手段。

vector::at() 会抛异常,operator[] 不会检查
越界访问本身不会自动报错,关键看用的是哪个接口。vec.at(i) 在 debug 和 release 模式下都会做边界检查,越界时抛 std::out_of_range 异常;而 vec[i] 在任何模式下都不检查——它只是指针偏移,越界后行为未定义(可能读到垃圾值、崩溃、或看似正常运行)。
常见错误现象:release 模式下程序“偶尔跑通”,debug 模式下却 crash 或断言失败,往往就是混用了 [] 和 at(),又没意识到检查逻辑只在 at() 里。
- 调试阶段建议统一用
at(),快速暴露索引问题 - 性能敏感循环中若已确保索引合法,可用
[]避免函数调用开销 - Clang/GCC 的
-D_GLIBCXX_DEBUG可为[]启用 debug 检查,但仅限 libstdc++ 且仅 debug 构建有效
MSVC 的 _ITERATOR_DEBUG_LEVEL 影响 debug 断言
在 Visual Studio 下,debug 模式默认开启迭代器调试(_ITERATOR_DEBUG_LEVEL=2),此时 vector::operator[] 仍不检查,但 vector::begin() + i 这类随机访问迭代器操作一旦越界,会在运行时触发断言(vector iterators incompatible 或直接 abort)。
release 模式下该宏被设为 0,所有迭代器调试逻辑被剥离,越界访问彻底变成未定义行为。
立即学习“C++免费学习笔记(深入)”;
- 不要依赖 MSVC debug 断言来“发现”越界——它不覆盖所有场景(比如纯
vec[i]就不触发) - 跨平台项目慎用
_ITERATOR_DEBUG_LEVEL相关断言,GCC/Clang 无等效机制 - 启用 /RTC1(运行时检查)可捕获部分栈上越界,但对 vector 堆内存越界无效
AddressSanitizer 是跨模式通用的越界检测手段
编译时加 -fsanitize=address(GCC/Clang)或 /fsanitize=address(MSVC 2019+),能让 vector 越界在 debug 和 release 下都立刻报错,输出详细堆栈和越界偏移量。
这是目前最可靠、最贴近真实问题的检测方式,比依赖编译模式差异更可控。
- ASan 会略微降低运行速度、增加内存占用,但开发/CI 阶段值得开启
- 注意:ASan 无法检测未初始化变量读取(那是 UBSan 的事),专注内存越界
- Linux/macOS 默认支持;Windows 需 VS 2019+ 且链接器支持 Sanitizer 运行时
越界后“没报错”不等于“安全”
尤其在 release 模式下,vector 越界常表现为静默错误:读到相邻对象的内存(导致逻辑错乱)、写覆盖其他 vector 的 size 字段(后续 push_back 崩溃)、或踩中 guard page 触发 SIGSEGV。这些都不会打印“越界”字样,只会表现为偶发 crash 或计算结果漂移。
真正棘手的不是 crash,而是那些“看起来还行”的越界——它们躲过测试,上线后在特定数据分布下才暴露。
- 静态分析工具(如 clang++ -fsanitize=undefined)能抓部分编译期可判的越界,但对运行时计算索引无效
- 单元测试里对 vector 访问加
assert(i 是低成本防御手段 - 注意 reserve() 不改变 size(),越界访问 reserved 但未 construct 的元素仍是未定义行为








