Что происходит, когда оператор [] терпит неудачу, и мне нужно подтверждение этого?

#include <iostream> 

int main() {
  int a[] = { 21, 213, 45 };
  static_assert(a[22], "error for a\n");
  return (0);
}

У меня есть таблица поиска в виде массива int, мне нужно проверить во время компиляции, может ли использование оператора [] привести к чтению, выходящему за рамки.

Я знаю, что static_assert нужны в основном две вещи:

  • постоянное выражение
  • данное выражение должно возвращать bool или быть конвертируемым/эквивалентным bool

Теперь в g++ 4.8.1 initializer_list должно быть константным выражением в C++11, и я не знаю, сколько раз я видел конструкцию if, написанную вот так if(arr[N]){...}; так что не так с этим утверждением?


person user2485710    schedule 10.12.2013    source источник
comment
Аргумент для статического утверждения должен быть разрешимым во время компиляции. a представляет собой массив ints, a[22] возвращает int, значение которого не будет известно до времени выполнения. Тот факт, что это за пределами, не помешает вам изучить его. По сути, почти всегда будет известно, находится ли доступ к массиву за пределами границ, только во время выполнения, так что это неподходящее место для static_assert.   -  person Grimm The Opiner    schedule 10.12.2013


Ответы (5)


Я думаю, вы можете обобщить то, что хотите, с помощью небольшой магии шаблонов.

template<typename T,int N> constexpr bool bounds_check(T (&array)[N], int i)
{
    return i < N;
}

Посмотрите это в действии: http://ideone.com/kj51N0.

person Mark Ransom    schedule 10.12.2013

Доступ за пределы массива является неопределенным поведением. Так что буквально все может случиться.

Статические утверждения связаны с ошибками во время компиляции. Это не будет зафиксировано до времени выполнения: слишком поздно.

person Bathsheba    schedule 10.12.2013
comment
поэтому наличие initializer_list со свойством быть постоянным выражением здесь бесполезно? На мой взгляд, это пустая трата информации во время компиляции, мне трудно поверить, что мне нужно дождаться времени выполнения, чтобы проверить это. - person user2485710; 10.12.2013

a[22] не является постоянным выражением. Кроме того, у него нет проверки диапазона, потому что доступ к собственным массивам перезаписывается компилятором в *(a + 22). Чтобы получить проверку диапазона, вам нужно собрать a как std::array, плюс в библиотеке C++ должна быть включена проверка диапазона, что некоторые делают, но только в режиме отладки.

Я думаю, что здесь бы сработало, если бы вы сделали static_assert(sizeof(a)/sizeof(*a) > 22, "a not large enough")

person Zan Lynx    schedule 10.12.2013
comment
так что initializer_list бесполезен для утверждения? - person user2485710; 10.12.2013
comment
@ Вирсавия: я не пробовал. - person Zan Lynx; 10.12.2013
comment
@user2485710: user2485710: я не понимаю, какое отношение имеет initializer_list к вопросу. - person Zan Lynx; 10.12.2013
comment
@ZanLynx это постоянное выражение ... и я пробовал, но это не помогло и ничего не изменило в уравнении. - person user2485710; 10.12.2013
comment
@ user2485710: инициализатор может быть постоянным, но то, что было инициализировано, - нет. - person Zan Lynx; 10.12.2013

Я думаю, вы можете использовать:

int a[] = { 21, 213, 45 };
static_assert(sizeof(a)/sizeof(a[0]) > 22, "error for a\n");
return (0);

Но это очень странная проверка. Это работает, только если индекс (22) и размер a известны во время компиляции.

person ikegami    schedule 10.12.2013

template<std::size_t Index, typename T, std::size_t N>
T& at( T(&a)[N] ) {
  static_assert( Index < N, "Out of bounds" );
  return a[Index];
}
template<std::size_t Index, typename T, std::size_t N>
T& at( std::array<T,N>& a ) {
  static_assert( Index < N, "Out of bounds" );
  return a[Index];
}
template<std::size_t Index, typename T, std::size_t N>
T const& at( std::array<T,N> const& a ) {
  static_assert( Index < N, "Out of bounds" );
  return a[Index];
}

использовать:

int main() {
  int a[] = { 21, 213, 45 };
  int x = at<22>(a); // fails to compile
  return (0);
}
person Yakk - Adam Nevraumont    schedule 10.12.2013