关于 std::vector 的下标越界检查

C语言(加了层语法糖的汇编)为了性能并不支持数组的越界检查,每次检查会多付出2-3倍的时间。

而vector以at的形式支持越界检查,但也支持C语言风格的[]高效访问,没错C++提供了足够的自由。

当要获取 std::vector 的第 n 个元素,下面几种方式都可以:

 
  1. std::vector vec;

  2. size_t n = 1;

  3. int & i = vec[n];

  4. int & j = *(vec.begin() + n);

  5. int & k = vec.at(n);

但是如果 n 超过了 vector 的下标范围,在几种方式的结果就有区别了。

在 linux 平台只有 at(n) 会抛出 std::out_of_range 异常,而其他两个都不会。

 查看标准模板库代码,可以看到:

 
  1. // element access

  2. /**

  3. * @brief Subscript access to the data contained in the %vector.

  4. * @param n The index of the element for which data should be

  5. * accessed.

  6. * @return Read/write reference to data.

  7. *

  8. * This operator allows for easy, array-style, data access.

  9. * Note that data access with this operator is unchecked and

  10. * out_of_range lookups are not defined. (For checked lookups

  11. * see at().)

  12. */

  13. reference

  14. operator[](size_type __n)

  15. { return *(this->_M_impl._M_start + __n); }

有说明:通过 operator[] 获取数组元素,不会检查下标有效性,需要检查的时候使用 at 接口

在 windows 平台 VS 环境下,都会抛出异常,VC 下的标准库是这样现实的:

 
  1. reference operator[](size_type _Pos)

  2. { // subscript mutable sequence

  3.  
  4. #if _HAS_ITERATOR_DEBUGGING

  5. if (size() <= _Pos)

  6. {

  7. _DEBUG_ERROR("vector subscript out of range");

  8. _SCL_SECURE_OUT_OF_RANGE;

  9. }

  10. #endif /* _HAS_ITERATOR_DEBUGGING */

  11. _SCL_SECURE_VALIDATE_RANGE(_Pos < size());

  12.  
  13. return (*(_Myfirst + _Pos));

  14. }

在 Debug 配置下, _HAS_ITERATOR_DEBUGGING 默认定义为 1,但是即使强制定义为 0,也有异常,因为还有一个 _SCL_SECURE_VALIDATE_RANGE 检查。所以即使在 Release 配置下,下标检查也是存在的。

如果把上面的代码中的“引用”符号去掉,像这样:

 
  1. std::vector vec;

  2. size_t n = 1;

  3. int i = vec[n];

  4. int j = *(vec.begin() + n);

  5. int k = vec.at(n);

那么 at(n) 仍然会抛出 std::out_of_range 异常,其他两个会出现什么情况呢,也许是内存访问异常,也许是其他诡异的错误。

在 vec 非空的情况下,即使下标越界,也有可能对应的内存是可读写的,至于读到的是什么内容,或者写到什么地方,就是随机事件了。

所以尽量用 at 接口,让错误尽早暴露出来。

源链接:https://blog.csdn.net/luansxx/article/details/10194171

你可能感兴趣的:(关于 std::vector 的下标越界检查)