Какво се случва, когато операторът [] се провали и имам нужда от твърдение за това?

#include <iostream> 

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

Имам справочна таблица, оформена като масив от int, трябва да проверя по време на компилиране дали използването на оператора [] може евентуално да доведе до четене, което е извън обхвата.

Знам, че static_assert се нуждае основно от 2 неща:

  • постоянен израз
  • даденият израз трябва да върне 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
така че инициализатор_списък е безполезен за твърдение? - person user2485710; 10.12.2013
comment
@Bathsheba: Не го пробвах. - person Zan Lynx; 10.12.2013
comment
@user2485710: Не виждам как инициализатор_списък е подходящ за въпроса. - 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