如何使 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 已经进行了边界检查。这可以在<vector>
标头中看到:
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中进行