应优先使用 std::vector::at() 替代 [] 运算符,因其越界时抛出 std::out_of_range 异常,而 [] 不检查导致未定义行为;开发测试阶段推荐 at(),生产环境热路径可换回 [] 但需确保安全。

用 std::vector::at() 替代 [] 运算符
std::vector::at() 在访问越界时会抛出 std::out_of_range 异常,而 [] 运算符完全不检查——哪怕下标是负数或远超容量,行为都是未定义的(可能崩溃、读到垃圾值、甚至看似“正常”运行)。这在调试阶段尤其危险,因为问题不会立刻暴露。
实操建议:
- 开发和测试阶段,优先用
at()替代[],尤其在索引来自用户输入、计算结果或循环变量时 - 捕获异常不是必须的,但至少要确保编译器开启异常支持(默认开启),且不要忽略抛出的异常
-
at()有轻微性能开销(一次边界比较),生产环境高频热路径可酌情换回[],但前提是已通过静态分析或断言确认安全
循环中始终用 size() 而非硬编码长度
硬编码数组长度(如 for (int i = 0; i )极易与实际容器大小脱节——删了元素、改了初始化、换了容器类型,都可能让循环越界。C++ 中推荐用 <code>container.size() 动态获取当前有效长度。
注意点:
-
std::vector、std::array、std::string等都提供size(),返回size_type(通常是size_t),别用int接收,否则可能触发隐式转换警告或比较问题 - 避免写
i :当 <code>v为空时,v.size()是0u,减 1 会绕成极大正数(无符号回绕),导致循环失控 - 更安全的写法是
i 或使用范围 for 循环(见下一条)
优先用范围 for 循环替代传统下标循环
只要不需要索引本身,范围 for 循环(for (const auto& x : container))天然规避下标越界问题——它由容器自己控制迭代边界,不暴露索引变量。
适用场景:
- 只读遍历、简单处理每个元素
- 配合
std::span(C++20)或gsl::span对原始数组做安全视图封装后,也能用于裸数组 - 若真需要索引,可用
for (size_t i = 0; i ,或借助 <code>std::views::enumerate(C++23)
对裸数组用 std::span 封装再操作
C 风格数组(如 int arr[5])没有 size() 方法,传参后还会退化为指针,彻底丢失长度信息。这是越界高发区。
解决方式:
- C++20 起,用
std::span<int></int>包裹裸数组:std::span arr_span{arr},它自动推导长度,支持size()、at()、范围 for - 若无法用 C++20,可用
std::array替代裸数组(编译期定长、带完整容器接口),或手动传长度参数并严格校验 - 禁用
sizeof(arr)/sizeof(arr[0])计算长度——该技巧仅在数组作用域内有效,一旦传入函数就失效
越界问题最难缠的不是崩溃,而是“看起来没问题”。真正安全的做法不是靠人盯住每处下标,而是把边界检查交给语言机制(at())、容器契约(size())和现代工具(std::span)。一旦放松对裸指针和硬编码长度的警惕,静态分析和 ASan 都救不了你。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











