GCC“调试”版本中的std::数组的绑定检验

时间:2021-05-18 07:04:38

Benefits of C++11 std::arrays when programming have been explained by experts, but there is one thing I would like to get from the compiler. Ability to turn ON range check that is default when using .at() while compiling the code that uses [].

c++ 11 std的好处::数组在编程时已经被专家解释过了,但是我想从编译器中得到一件事。在编译使用[]的代码时,能够在使用.at()时打开默认的范围检查。

It could be beneficial for checking range violations especially for multidimensional arrays because in that case it is less likely that range violation will cause segfault(because you often own memory around the inner array so [5000][-123] will still likely point to memory that you own).

它可能有助于检查范围违规,特别是对于多维数组,因为在这种情况下,范围违规将导致segfault的可能性更小(因为您经常拥有内部数组的内存,所以[5000][-123]仍然可能指向您所拥有的内存)。

So I would like to know if there is a switch that will compile into machine code that checks ranges:

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

    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

If you ask why I don't switch to .at() - I might need the performance, also I have a lot of code with [] already written and I'm not smart enough to smart to do replace for 1D let alone 2D arrays.

如果你问我为什么不切换到。at()——我可能需要性能,而且我有很多已经写了[]的代码,而且我还不够聪明,不能智能地替换1D,更不用说2D数组了。

I use GCC 4.6

我使用GCC 4.6

4 个解决方案

#1


2  

You can emulate the behaviour you desire:

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

#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

It doesn't perfectly match std::array, but that could be fixed if it matters to you. Then replace all reference to std::array with my_array and you'll get range checked operator[] for debug builds.

它并不完全匹配std::array,但是如果它对您很重要,那么它可以被修复。然后用my_array替换对std::数组的所有引用,您将获得用于调试构建的range check操作符[]。

(I'd have used template aliases to simplify the NDEBUG code, but I can't actually test that yet on my compiler)

(我会使用模板别名来简化NDEBUG代码,但我还不能在编译器上测试)

#2


5  

It looks like the array that comes with gcc 4.6 doesn't have a debug mode yet. Understandable since C++11 support is still experimental.

看起来gcc 4.6附带的数组还没有调试模式。可以理解,因为c++ 11支持还处于试验阶段。

There is a flag _GLIBCXX_DEBUG which is usually used to turn on debug mode. If you look at /usr/include/c++/4.6/debug/vector:313 you'll see operator[] has:

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

__glibcxx_check_subscript(__n);

Now, this may be uber-evil (and I mean really evil) but it looks like we can conditionally add this to array. Change lines 148-154 of /usr/include/c++/4.6/array from:

现在,这可能是超级邪恶(我的意思是真正的邪恶),但是看起来我们可以有条件地将它添加到数组中。更改/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]; }

to:

:

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];
}

This means you can enable bounds checking for array the same way you do for vector and other stl debugging - by adding -D_GLIBCXX_DEBUG to your compile line. E.g.:

这意味着您可以通过在编译行中添加- d_glibcxx_debug来启用数组的边界检查,就像对vector和其他stl调试一样。例如:

g++ someAwesomeProgram.cpp -D_GLIBCXX_DEBUG

I just had a look at gcc trunk and apparently there is no reference to _GLIBCXX_DEBUG for array yet :(. http://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/include/std/array

我刚刚查看了gcc主干,显然还没有对数组的_GLIBCXX_DEBUG进行引用:(。http://gcc.gnu.org/svn/gcc/trunk/libstdc + + v3 / include / std /数组

Hopefully it's not too far away. I imagine we will have safe iterators and all that for array in debug mode soon enough. In the meantime, this can be our little secret :-).

希望不会太远。我想我们很快就会在调试模式下拥有安全的迭代器和所有这些。同时,这也是我们的小秘密:-)。

#3


3  

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));
}

Should do the job. Just use at(arr, pos) consistently throughout the codebase.

应该做这项工作。只需在整个代码基中始终使用at(arr, pos)。

#4


2  

It is not so much gcc as libstdc++ the Standard Library implementation that comes with gcc (you are free to use another implementation if you wish).

它与其说是gcc,不如说是libstdc+标准库实现(如果您愿意,您可以*地使用另一个实现)。

libstdc++ has a preprocessor flag that can be used for debugging -D_GLIBCXX_DEBUG, however you should note that this debug mode changes the ABI of the types, and thus you need to link with libraries that have also been compiled with this debug mode enabled. It can be painful.

libstdc++有一个预处理器标志,可用于调试-D_GLIBCXX_DEBUG,但是您应该注意,此调试模式更改了类型的ABI,因此您需要与使用此调试模式编译的库进行链接。它可以是痛苦的。

libc++ is another implementation (nigh C++11 compliant) that is first aimed at Clang but should work on any compliant compiler. It aims at maintaining ABI compatibility whether debugging is enabled or not. It's not fully stable outside of OS X though (mostly because of locale) so might not be usable in your environment.

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

Note that both those libraries are Free Software, so if the check is not implemented, you can perfectly submit a patch.

注意,这两个库都是*软件,所以如果没有实现检查,您可以完美地提交一个补丁。

#1


2  

You can emulate the behaviour you desire:

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

#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

It doesn't perfectly match std::array, but that could be fixed if it matters to you. Then replace all reference to std::array with my_array and you'll get range checked operator[] for debug builds.

它并不完全匹配std::array,但是如果它对您很重要,那么它可以被修复。然后用my_array替换对std::数组的所有引用,您将获得用于调试构建的range check操作符[]。

(I'd have used template aliases to simplify the NDEBUG code, but I can't actually test that yet on my compiler)

(我会使用模板别名来简化NDEBUG代码,但我还不能在编译器上测试)

#2


5  

It looks like the array that comes with gcc 4.6 doesn't have a debug mode yet. Understandable since C++11 support is still experimental.

看起来gcc 4.6附带的数组还没有调试模式。可以理解,因为c++ 11支持还处于试验阶段。

There is a flag _GLIBCXX_DEBUG which is usually used to turn on debug mode. If you look at /usr/include/c++/4.6/debug/vector:313 you'll see operator[] has:

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

__glibcxx_check_subscript(__n);

Now, this may be uber-evil (and I mean really evil) but it looks like we can conditionally add this to array. Change lines 148-154 of /usr/include/c++/4.6/array from:

现在,这可能是超级邪恶(我的意思是真正的邪恶),但是看起来我们可以有条件地将它添加到数组中。更改/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]; }

to:

:

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];
}

This means you can enable bounds checking for array the same way you do for vector and other stl debugging - by adding -D_GLIBCXX_DEBUG to your compile line. E.g.:

这意味着您可以通过在编译行中添加- d_glibcxx_debug来启用数组的边界检查,就像对vector和其他stl调试一样。例如:

g++ someAwesomeProgram.cpp -D_GLIBCXX_DEBUG

I just had a look at gcc trunk and apparently there is no reference to _GLIBCXX_DEBUG for array yet :(. http://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/include/std/array

我刚刚查看了gcc主干,显然还没有对数组的_GLIBCXX_DEBUG进行引用:(。http://gcc.gnu.org/svn/gcc/trunk/libstdc + + v3 / include / std /数组

Hopefully it's not too far away. I imagine we will have safe iterators and all that for array in debug mode soon enough. In the meantime, this can be our little secret :-).

希望不会太远。我想我们很快就会在调试模式下拥有安全的迭代器和所有这些。同时,这也是我们的小秘密:-)。

#3


3  

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));
}

Should do the job. Just use at(arr, pos) consistently throughout the codebase.

应该做这项工作。只需在整个代码基中始终使用at(arr, pos)。

#4


2  

It is not so much gcc as libstdc++ the Standard Library implementation that comes with gcc (you are free to use another implementation if you wish).

它与其说是gcc,不如说是libstdc+标准库实现(如果您愿意,您可以*地使用另一个实现)。

libstdc++ has a preprocessor flag that can be used for debugging -D_GLIBCXX_DEBUG, however you should note that this debug mode changes the ABI of the types, and thus you need to link with libraries that have also been compiled with this debug mode enabled. It can be painful.

libstdc++有一个预处理器标志,可用于调试-D_GLIBCXX_DEBUG,但是您应该注意,此调试模式更改了类型的ABI,因此您需要与使用此调试模式编译的库进行链接。它可以是痛苦的。

libc++ is another implementation (nigh C++11 compliant) that is first aimed at Clang but should work on any compliant compiler. It aims at maintaining ABI compatibility whether debugging is enabled or not. It's not fully stable outside of OS X though (mostly because of locale) so might not be usable in your environment.

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

Note that both those libraries are Free Software, so if the check is not implemented, you can perfectly submit a patch.

注意,这两个库都是*软件,所以如果没有实现检查,您可以完美地提交一个补丁。