繁体   English   中英

在GCC的“Debug”版本中绑定检查std :: array

[英]Bound checking of std::array in “Debug” version of GCC

专家解释了编程时C ++ 11 std::array的优点,但我希望从编译器中获得一些东西。 能够打开在编译使用[]的代码时使用.at()时默认的范围检查。

检查范围违规尤其是多维数组可能是有益的,因为在这种情况下,范围违规不太可能导致segfault(因为你经常在内部数组周围拥有内存,所以[5000][-123]仍然可能指向内存你拥有的)。

所以我想知道是否有一个开关可以编译成检查范围的机器代码:

    const uint32_t dim1=10*1000,dim2=3;
    std::array<std::array<int, dim2>, dim1> test_2Darray;
    int undefined_value=test_2Darray[dim2-1][dim1-1];
    std::cout<<"ouch ("<<undefined_value<<")"<<std::endl;
    int ok_value=test_2Darray[dim1-1][dim2-1];
    std::cout<<"OK   ("<<ok_value<<")"<<std::endl;
    //  test_2Darray.at(dim2-1).at(dim1-1); -->terminate called after throwing an instance of 'std::out_of_range'
    //      what():  array::at

如果你问为什么我不切换到.at() - 我可能需要性能,我也有很多代码[]已经写好了,我不聪明,不能聪明地替换1D更不用说2D了阵列。

我使用GCC 4.6

看起来gcc 4.6附带的数组还没有调试模式。 可以理解,因为C ++ 11支持仍然是实验性的。

有一个标志_GLIBCXX_DEBUG ,通常用于打开调试模式。 如果你看一下/usr/include/c++/4.6/debug/vector:313,你会看到operator[]有:

__glibcxx_check_subscript(__n);

现在,这可能是超级邪恶(我的意思是真的很邪恶),但看起来我们可以有条件地将它添加到数组中。 更改/usr/include/c++/4.6/array的第148-154行:

reference
operator[](size_type __n)
{ return _M_instance[__n]; }

const_reference
operator[](size_type __n) const
{ return _M_instance[__n]; }

至:

reference
operator[](size_type __n)
{
#ifdef _GLIBCXX_DEBUG
    __glibcxx_check_subscript(__n);
#endif
    return _M_instance[__n];
}

const_reference
operator[](size_type __n) const
{
#ifdef _GLIBCXX_DEBUG
    __glibcxx_check_subscript(__n);
#endif
    return _M_instance[__n];
}

这意味着您可以像对向量和其他stl调试一样启用对数组的边界检查 - 通过向编译行添加-D_GLIBCXX_DEBUG 例如:

g++ someAwesomeProgram.cpp -D_GLIBCXX_DEBUG

我只是看看gcc的树干,显然没有提到但_GLIBCXX_DEBUG数组:(。 http://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/include/std/array

希望它不会太远。 我想我们将有足够的安全迭代器以及调试模式中的所有数组。 与此同时,这可能是我们的小秘密:-)。

template<class T, std::size_t N>
T const& at(std::array<T,N> const& arr, std::size_t pos){
#ifndef NDEBUG
  // debug versions, automatically range checked
  return arr.at(pos);
#else
  // release version, unchecked
  return arr[pos];
#endif
}    

template<class T, std::size_t N>
T& at(std::array<T,N>& arr, std::size_t pos){
  typedef std::array<T,N> const& const_array;
  // const_cast of the return is safe here because be pass a non-const array
  // const_cast for the argument is needed to avoid infinite recursion
  return const_cast<T&>(at(const_cast<const_array>(arr), pos));
}

应该做的工作。 只需at(arr, pos)整个代码库中使用at(arr, pos)

您可以模仿您想要的行为:

#include <array>
#include <cassert>
#include <iostream>

#ifndef NDEBUG
template <typename T, std::size_t N>
struct my_array : std::array<T,N> {
 T& operator[](std::size_t n) {
   assert(n < N);
   return (*static_cast<std::array<T,N>*>(this))[n];
 }
 const T& operator[](std::size_t n) const {
   assert(n < N);
   return (*static_cast<const std::array<T,N>*>(this))[n];
 }
};
#else
// I would use Alias templates here, but isn't supported on my compiler yet!
template <typename T, std::size_t N>
struct my_array : std::array<T,N> {
};
#endif

它与std::array不完全匹配,但如果对你很重要,可以修复它。 然后用my_array替换对std::array所有引用,你将获得调试版本的范围检查operator[]

(我已经使用模板别名来简化NDEBUG代码,但我实际上无法在我的编译器上测试它)

libstdc++的是gcc附带的标准库实现(如果你愿意,可以自由使用另一个实现)。

libstdc++有一个预处理程序标志,可用于调试-D_GLIBCXX_DEBUG ,但是您应该注意,此调试模式会更改类型的ABI,因此您需要链接已启用此调试模式编译的库。 这可能很痛苦。

libc++是另一个实现(符合C ++ 11标准),它首先针对Clang,但应该适用于任何兼容的编译器。 它旨在维护ABI兼容性,无论是否启用调试。 但它在OS X之外并不完全稳定(主要是因为语言环境),因此可能无法在您的环境中使用。

请注意,这两个库都是自由软件,因此如果没有实现检查,您可以完美地提交补丁。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM