




vector::at() 在越界时抛 std::out_of_range 异常,operator[] 不检查越界、行为未定义;debug 模式下部分实现可能增强检查但不可依赖;at() 有异常开销但通常可忽略,应先 profile 再优化。
vector::at() 在索引超出 size() 范围时抛出 std::out_of_range 异常;而 operator[] 完全不检查,行为是未定义的(UB)。这意味着用 operator[] 访问 v[100] 时,即使 v.size() == 5,编译器不会报错、运行时也不一定崩溃——可能读到垃圾值,也可能意外覆盖相邻内存,调试极难定位。
某些标准库实现(如 libstdc++ 的 debug mode 或 MSVC 的 _ITERATOR_DEBUG_LEVEL=2)会在 debug 下为 operator[] 加额外检查,但这是非标准行为,不可依赖。release 模式下一律无检查。所以不能靠“本地跑通”判断越界是否安全。
at()
operator[] 是显式承担越界风险,常见于性能敏感且逻辑已确保安全的场景(如循环内反复访问,且索引由 size() 控制)at() 做更准的流敏感检查,对 operator[] 几乎无能为力除了多一次 if (i >= size()) 判断,at() 还隐含异常处理机制的准备成本:编译器可能禁用部分优化,栈展开信息需保留。在 tight loop 中频繁调用 at() 确实有可观开销。但多数业务代码里,这点开销远小于一次缓存未命中或分支预测失败。
operator[],先 profile 确认它真是瓶颈data()[i] 替代 operator[](更裸,但语义等价)data(),仍需自己保证 i ,否则仍是 UB
很多人封装 vector 写个 get(i) 方法,却忘了转发 at() 的异常规格说明(noexcept 与否),或误把 operator[] 当作“默认安全”接口暴露出去。结果上层调用者以为不会抛异常,实际却因越界触发 UB。
at(),就该声明 throw(std::out_of_range) 或 C++11 后用 noexcept(false)
assert(i ),那它只在 debug 生效,release 下失效——这和 operator[] 本质一样,不是“安全替代”
operator() 带检查、unchecked() 供性能场景,这种分离更明确at() 不代表懒,用 operator[] 也不代表快——关键在上下文里是否真能排除越界可能。