索引有效的核心条件是检查 i 是否满足 0 ≤ i && i
直接判断索引是否有效,核心就一条:检查
i是否满足0 。C++ 不会替你做这件事,越界访问就是未定义行为——崩溃、数据错乱、甚至看似正常但逻辑已毁,全看运气。原生数组怎么判断索引有效性
原生数组(如
int arr[10])没有内置长度信息,sizeof(arr)/sizeof(arr[0])只在定义作用域内可靠;传参后退化为指针,sizeof就失效了。
- 必须显式传入或维护
size变量,不能靠数组名推断- 写成
if (i >= 0 && i ,别用 <code>i 这类错误写法- 注意类型匹配:
size是size_t,而i是int时,i 在 <code>i为负时可能因无符号提升导致恒真(比如-1 实际为 <code>4294967295U → false)- 推荐统一用
size_t做索引变量,或显式强转:static_cast<size_t>(i) </size_t>std::array 和 std::vector 的安全访问方式
std::array和std::vector提供了.at()方法,它会在运行时检查索引,越界时抛出std::out_of_range异常。
arr.at(i)比arr[i]多一次边界检查,但只在你需要确定性失败行为时才用- Debug 模式下,某些 STL 实现(如 MSVC)会让
operator[]触发断言;Release 下仍不检查,和原生数组一样- 如果性能敏感且逻辑已确保索引合法,用
[];否则优先用.at()避免静默越界std::vector的.size()是 O(1),可放心调用循环中常见的索引越界陷阱
循环条件写错是最高频的越界来源,尤其容易忽略“等于”边界的危害。
for (int i = 0; i —— 错!应为 <code>ifor (size_t i = 0; i —— 更危险!当 <code>v.size() == 0时,i 为真,进入循环后 <code>i变成1(因为size_t无符号),再访问v[1]必然越界- 遍历建议统一用范围 for 循环:
for (const auto& x : v),彻底避开索引计算- 若必须用索引,写成
for (size_t i = 0; i != v.size(); ++i)比更安全(避免浮点或有符号混用)assert 和静态分析能帮你多少
assert(i 只在 Debug 版本生效,Release 中被移除,不能当作运行时防护。
- 适合开发阶段快速暴露逻辑错误,但不能替代真实边界检查
- Clang 的
-fsanitize=address或 GCC 的-fsanitize=undefined可在运行时捕获越界,但会显著降低性能,仅用于测试- 静态分析工具(如 clang-tidy 的
cppcoreguidelines-pro-bounds-array-to-pointer-decay)能发现部分明显越界,但对动态索引无能为力- 真正可靠的防线,永远是你自己写的
if (i 判断,以及用 <code>std::vector::at()或范围 for 替代裸索引最易被忽略的点是:原生数组传参后彻底丢失长度信息,而很多人还在函数里盲目用
sizeof。一旦跨作用域,你就只能靠约定或额外参数来保命。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!












