Bound checking of std::array in "Debug" version of GCC

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.

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_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:

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.:

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

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 :-).


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.


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.

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

Tags:

C++

Arrays

C++11