Связанная проверка std :: array в «отладочной» версии GCC - PullRequest
8 голосов
/ 18 ноября 2011

Преимущества C ++ 11 std::array s при программировании были объяснены экспертами, но есть одна вещь, которую я хотел бы получить от компилятора.Возможность включить проверку диапазона, которая используется по умолчанию при использовании .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

Если вы спросите, почему я не 't переключиться на .at() - мне может понадобиться производительность, также у меня много кода с уже написанным [], и я недостаточно умен, чтобы уметь заменить 1D, не говоря уже о 2D-массивах.

Я использую GCC 4.6

Ответы [ 4 ]

5 голосов
/ 04 декабря 2011

Похоже, что массив, который поставляется с gcc 4.6, еще не имеет режима отладки. Понятно, поскольку поддержка C ++ 11 все еще экспериментальна.

Существует флаг _GLIBCXX_DEBUG, который обычно используется для включения режима отладки. Если вы посмотрите на /usr/include/c++/4.6/debug/vector:313, то увидите, что operator[] имеет:

__glibcxx_check_subscript(__n);

Теперь, это может быть супер-злым (и я имею в виду действительно злом), но похоже, что мы можем условно добавить это в массив. Измените строки 148-154 файла /usr/include/c++/4.6/array с:

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 в строку компиляции. E.g.:

g++ someAwesomeProgram.cpp -D_GLIBCXX_DEBUG

Я только что посмотрел на транк gcc и, видимо, пока нет ссылки на _GLIBCXX_DEBUG для массива :(. http://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/include/std/array

Надеюсь, это не слишком далеко. Я предполагаю, что у нас будут безопасные итераторы и все это для массива в режиме отладки достаточно скоро. А пока это может быть нашим маленьким секретом: -).

3 голосов
/ 18 ноября 2011
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) последовательно по всей базе кода.

2 голосов
/ 18 ноября 2011

Это не столько gcc, сколько libstdc++ стандартная реализация библиотеки, которая поставляется с gcc (вы можете использовать другую реализацию, если хотите).

libstdc++ имеет флаг препроцессора, который можно использовать для отладки -D_GLIBCXX_DEBUG , однако следует помнить, что этот режим отладки изменяет ABI типов, и, таким образом, вам нужно связываться с библиотеками, которые имеют также был скомпилирован с включенным режимом отладки. Это может быть больно.

libc++ - это другая реализация (почти совместимая с C ++ 11), которая сначала нацелена на Clang, но должна работать на любом совместимом компиляторе. Он направлен на поддержание совместимости ABI независимо от того, включена отладка или нет. Хотя он не полностью стабилен вне OS X (в основном из-за локали), поэтому его нельзя использовать в вашей среде.

Обратите внимание, что обе эти библиотеки являются свободными программами, поэтому, если проверка не реализована, вы можете безошибочно отправить исправление.

2 голосов
/ 18 ноября 2011

Вы можете подражать желаемому поведению:

#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, но это можно исправить, если это важно для вас. Затем замените все ссылки на std::array на my_array, и вы получите диапазон проверки operator[] для отладочных сборок.

(я бы использовал псевдонимы шаблонов для упрощения кода NDEBUG, но я пока не могу это проверить на моем компиляторе)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...