如何使 std::vector 的 operator[] 编译在 DEBUG 中而不是在 RELEASE 中进行边界检查

Posted

技术标签:

【中文标题】如何使 std::vector 的 operator[] 编译在 DEBUG 中而不是在 RELEASE 中进行边界检查【英文标题】:How to make std::vector's operator[] compile doing bounds checking in DEBUG but not in RELEASE 【发布时间】:2009-08-17 20:57:18 【问题描述】:

我正在使用 Visual Studio 2008。

我知道 std::vector 使用 at() 函数进行边界检查,并且如果您尝试使用运算符 [] 不正确地访问某些内容(超出范围),则会出现未定义的行为。

我很好奇是否可以通过边界检查来编译我的程序。这样,operator[] 将使用 at() 函数并在超出范围时抛出 std::out_of_range。

release 模式编译时不会对 operator[] 进行边界检查,因此性能不会降低。

我开始考虑这个问题是因为我正在将使用 Borland C++ 编写的应用程序迁移到 Visual Studio,并且在一小部分代码中我有这个(i=0,j=1):

v[i][j]; //v is a std::vector<std::vector<int> >

向量'v'的大小是[0][1](所以向量的元素0只有一个元素)。这是未定义的行为,我知道,但 Borland 在这里返回 0,VS 正在崩溃。我更喜欢崩溃而不是返回 0,所以如果我可以通过抛出 std::out_of_range 异常来获得更多“崩溃”,那么迁移将更快完成(因此它会暴露 Borland 隐藏的更多错误)。

【问题讨论】:

【参考方案1】:

Visual Studio 2005 和 2008 已经在默认情况下对operator[] 进行边界检查, 调试和发布版本。

控制此行为的宏是_SECURE_SCL。将其设置为 0 以禁用边界检查。

他们目前在 VS2010 中的计划是在发布版本中默认禁用边界检查,但在调试中保持开启。 (宏也被重命名为_ITERATOR_DEBUG_LEVEL。我不知道是否有任何正式的文档可用,但已经提到了here 和here)

【讨论】:

+1 完美。你会在哪里找到像新名字这样的东西?只看新的头文件? 请确保始终使用 _SECURE_SCL。不一致的使用会导致未定义的行为,也就是崩溃。【参考方案2】:

启用标志 _GLIBCXX_DEBUG 以对 STL 容器进行边界检查,如下所述: http://gcc.gnu.org/onlinedocs/libstdc++/manual/debug_mode.html

【讨论】:

为什么 libstdc++ 宏可以在 Visual Studio 中工作?你不是说 C++ 标准库吗? libc++ 是否有与此等价的功能?【参考方案3】:

我问这个问题太早了,但我还是发布了答案,所以我分享了一些知识。

在调试模式下编译时,在 Visual Studio 中实现的 stl 已经进行了边界检查。这可以在&lt;vector&gt; 标头中看到:

reference operator[](size_type _Pos)
           // subscript mutable sequence

 #if _HAS_ITERATOR_DEBUGGING
        if (size() <= _Pos)
            
            _DEBUG_ERROR("vector subscript out of range");
            _SCL_SECURE_OUT_OF_RANGE;
            
 #endif /* _HAS_ITERATOR_DEBUGGING */
        _SCL_SECURE_VALIDATE_RANGE(_Pos < size());

        return (*(_Myfirst + _Pos));
        

所以有对向量类的边界检查。我没有查看其他容器,但我相信它们具有相同的机制。

【讨论】:

嗯。你在这篇文章上比我快 ;-) Same here :) 就是说,我很确定即使在 Release 中它也会继续执行此检查。您必须定义一个宏才能完全关闭它。【参考方案4】:

我现在无法访问任何 Windows 机器。但是,如果我在我的 mac os x 机器上查看 g++ 提供的 STL 实现,来自 /usr/include/c++/4.0.0/bits/stl_vector.h :

  // element access
  /**
   *  @brief  Subscript access to the data contained in the %vector.
   *  @param n The index of the element for which data should be
   *  accessed.
   *  @return  Read/write reference to data.
   *
   *  This operator allows for easy, array-style, data access.
   *  Note that data access with this operator is unchecked and
   *  out_of_range lookups are not defined. (For checked lookups
   *  see at().)
   */
  reference
  operator[](size_type __n)
   return *(begin() + __n); 

没有执行检查,事件虽然在调试模式。此代码中没有 _GLIBCXX_DEBUG 宏。

看看您自己的随 MSVC 交付的 STL 实现,看看做了什么。如果在任何情况下都没有进行检查......你别无选择,只能使用 at().. :-(

【讨论】:

MSVC 默认执行边界检查(在 VC8 和 9 both 中的调试和发布版本中,在 VC10 中仅在调试中) 你的答案没有深入迭代器推进的实现。【参考方案5】:

为了速度,C++ 将向量运算符[] 定义为不抛出异常。

我建议您在调试配置中测试应用程序一段时间,直到您确信主要的“隐藏”错误已消失。

【讨论】:

C++ 未定义如果 [] 超出范围会发生什么。这意味着实现执行边界检查是合法的,有些人这样做。

以上是关于如何使 std::vector 的 operator[] 编译在 DEBUG 中而不是在 RELEASE 中进行边界检查的主要内容,如果未能解决你的问题,请参考以下文章

如何使std :: vector的operator []编译在DEBUG中进行边界检查,但不在RELEASE中进行

如何将 xarray 转换为 std::vector?

如何将 std::vector 的容量限制为元素的数量

使 double 和 std::vector<double> 协变

如何在 omp 并行中使特定部件串行?

C++ 动态分配的 std::vector