Не используйте индекс массива, если индекс не является целочисленным константным выражением; используйте вместо этого gsl :: at ()

Я пытался создать пример кода в Microsoft Visual Studio, который выглядит так

int main()
{
    const size_t size = 10;
    int arr[size];

    for (size_t i = 0; i < size; ++i)
        arr[i] = i;

    return 0;
}

Теперь JetBrains ResharperC ++ выдает следующее предупреждение в строке arr[i] = i;

введите здесь описание изображения Не используйте индекс массива, если индекс не является целочисленным константным выражением; используйте вместо этого gsl :: at ()

Я не понимаю, что я имею в виду и как устранить это предупреждение.

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

Может ли кто-нибудь посоветовать или указать мне правильное направление?

РЕДАКТИРОВАТЬ: изменение цикла на:

for (size_t i = 0; i < size; ++i)
    arr[i] = 0;

по-прежнему выдает предупреждение.


person user32434999    schedule 17.08.2018    source источник
comment
Я думаю, он жалуется, что индекс (i в вашем случае) не является int. в зависимости от компилятора и архитектуры неиспользование int может иметь странные эффекты. поэтому всегда лучше использовать int, а не size_t при индексировании массива   -  person loonytune    schedule 17.08.2018
comment
@loonytune Изменение all size_t на int не решает проблемы.   -  person user32434999    schedule 17.08.2018
comment
С другой стороны, вы назначаете size_t для int [], что будет ужасно неправильно на каждой 64-битной архитектуре (потому что там sizeof (size_t) ›sizeof (int)).   -  person loonytune    schedule 17.08.2018
comment
просто для удовольствия, можете ли вы попробовать заменить arr [i] = ... на * (arr + i) = ...?   -  person loonytune    schedule 17.08.2018
comment
См. stackoverflow.com/questions/1951519/when -should-i-use-stdsize-t, вы должны использовать unsigned int, если хотите быть в безопасности.   -  person Korni    schedule 17.08.2018
comment
@loonytune и предупреждение исчезло ... Что это значит dies?   -  person user32434999    schedule 17.08.2018
comment
ну, * (arr + i) то же самое, что и арифметика указателей. возможно, jetbrains жалуется, что вы используете семантику массива с переменным индексом, хотя в вашем случае размер массива фиксирован. и, используя магию указателя, он больше этого не обнаруживает. другой эксперимент, попробуйте заменить объявление int arr [size] на int [] arr = (int []) malloc (sizeof (int) * size);   -  person loonytune    schedule 17.08.2018
comment
Это не компилируется   -  person user32434999    schedule 17.08.2018
comment
Это следствие двух ошибок проектирования языка C ++: 1) использование исключений для сообщения о логических ошибках; 2) использовать целое число без знака для размера массивов и индексов. Просто не обращайте на это внимания, это будет исправлено.   -  person Oliv    schedule 17.08.2018
comment
Хорошо! Спасибо, парни.   -  person user32434999    schedule 17.08.2018
comment
@Oliv А вы знаете, что такое gsl :: at ()?   -  person user32434999    schedule 17.08.2018
comment
@P i Я полагаю, они использовали стандартную семантику. an_array.at(index) эквивалентно if (index>=an_array.size()) throw a_logical_error{}; return an_array[index];   -  person Oliv    schedule 17.08.2018


Ответы (7)


В целом

for (size_t i = 0; i < size; ++i)
    arr[i] = something;

опасный. Вы не можете сказать, выйдет ли arr[i] за пределы массива. Вот почему Основные рекомендации C ++ предлагают вам использовать gsl::at(), поскольку он будет проверять границы, чтобы убедиться, что вы это делаете не выходить за пределы массива.

Однако это не единственное решение. Если вам просто нужен итератор по диапазону, вы можете использовать диапазон на основе цикла, например

for (const auto& e : arr)
    //e is each element of the array and is not mutable here

or

for (auto& e : arr)
    //e is each element of the array and is mutable here

А для случая, подобного вашему, когда вам нужно заполнить массив, вы можете использовать _6 _ нравится

std::iota(std::begin(arr), std::end(arr), 0);

и все это гарантированно не выйдет за пределы поля.

person NathanOliver    schedule 17.08.2018

Это предупреждение о том, что arr[i] не проверяет границы и вам следует использовать gsl::at(arr, i) из https://github.com/Microsoft/GSL, так как он более безопасен и проверяет границы.

person Alan Birtles    schedule 17.08.2018

Я думаю, что причина предупреждения в том, что operator[] не проверяет границы, а gsl::at() может.

Поскольку size известен во время компиляции, если индекс был constexpr, вы могли бы получить предупреждение, но если значение было определено во время выполнения, вы не можете. На мой взгляд, излишне.

person Kostas    schedule 17.08.2018

Доступ к элементу массива по индексу без проверки границ не считается хорошей практикой. Это прямой доступ к памяти, который небезопасен и может вызвать ошибку сегментации.

Для контейнера STL, такого как std::vector, есть _ 2_ функция-член, которая выполняет проверку границ и является рекомендуемым способом доступа к элементам.

В этом тривиальном примере вы можете проигнорировать это предупреждение. Но для нетривиального кода используйте std::vector. Но для массивов в стиле C вы можете загрузить и использовать gsl::at(), а также изучить другие его возможности.


Ссылки:
Основные принципы C ++
GSL (библиотека поддержки рекомендаций)

person Azeem    schedule 17.08.2018

Это не предупреждение (компилятора). Это одно из основных правил C ++, включенных в стороннюю среду IDE / инструмент анализа.

person Ron    schedule 17.08.2018

Это предупреждение, поскольку operator[] не проверяет границу, в отличие от at. В то время как в вашем случае код правильный, "небольшое" изменение может нарушить ваш цикл (int arr[2 * size];)

В вашем случае есть несколько хороших альтернатив с использованием итераторов (явно или неявно):

const size_t size = 10;
int arr[size];

std::iota(std::begin(arr), std::end(arr), 0);

or

int i = 0;
for (auto& e : arr) {
    e = i;
    ++i;
}
person Jarod42    schedule 17.08.2018

int array[] = {0, 1, 2};
for (auto element : array){
   if(element == 1){
   //.....
   }
}

Попробуйте приведенный выше код.

person Hieu Le    schedule 10.11.2020