std :: array: Почему нет предупреждения или ошибки в `at (-2)`? - PullRequest
1 голос
/ 06 апреля 2020

В книге сказано, что std::array безопаснее и проще, чем другие методы назначения.

Вот мой код:

#include<iostream>
#include<array>
using namespace std;

int main()
{
    array<int, 5> a = {1, 2, 3, 4, 5};
    a.at(-2) = 100;
    cout << a[-2] << endl;
    return 0;
}

Почему в этом коде нет предупреждений или ошибок

Ответы [ 3 ]

1 голос
/ 06 апреля 2020

std::array::at() принимает аргумент size_type, который обычно определяется в терминах некоторого типа unsinged, например std::size_t / unsigned long.

Фактический аргумент -2 имеет тип signed int, который неявно преобразуется в size_type при переходе к at() и становится действительным size_type числом; но только обернутый один. См. пример .

По умолчанию вы не получаете предупреждение / ошибку компилятора для неявного преобразования. Вы должны искать опции вашего компилятора, такие как G CC s -Wconversion, Wsign-conversion, et c. чтобы включить эти настройки. В вашем случае на G CC, -Wsign-conversion предупредит вас об этих преобразованиях; и в сочетании с -Werror эти предупреждения станут ошибками.

Обратите внимание на вывод компилятора вашего кода с флагами компилятора -std=c++11 -Werror -Wsign-conversion ( live ):

Вывод компилятора:

<source>: In function 'int main()':

<source>:6:10: error: unsigned conversion from 'int' to 'std::array<int, 5>::size_type' {aka 'long unsigned int'} changes value from '-2' to '18446744073709551614' [-Werror=sign-conversion]

    6 |     a.at(-2)=100;

      |          ^~

<source>:7:13: error: unsigned conversion from 'int' to 'std::array<int, 5>::size_type' {aka 'long unsigned int'} changes value from '-2' to '18446744073709551614' [-Werror=sign-conversion]

    7 |     cout<<a[-2]<<endl;

      |             ^~

cc1plus: all warnings being treated as errors

Вот еще один пример , который имитирует то же самое.


И, в at(), переданный аргумент проверяется по размеру массива. Здесь вы получите исключение времени выполнения типа std :: out_of_range , как описано в документации :

Если pos находится вне диапазона из контейнера выдается исключение типа std::out_of_range.

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

И, когда вы используете недопустимый индекс с оператором индекса [] например, a[-2], где преобразование -2 в size_type возвращает значение с циклическим изменением, результатом будет доступ за пределами допустимого диапазона и вызовет неопределенное поведение .

Надеюсь, это объяснение поможет!

1 голос
/ 07 мая 2020

Функция-член at выполняет проверку во время выполнения, а operator[] не проверяет (это намеренный дизайн).

Вы можете выполнить проверку во время компиляции, используя get:

#include <array>
using namespace std;

int main()
{
    array<int, 5> a = {1, 2, 3, 4, 5};
    get<1>(a) = 100;  // ok
    get<-2>(a) = 100; // error
    get<5>(a) = 100;  // error
}
0 голосов
/ 06 апреля 2020

доступ к недопустимому элементу std::array с .at приведет к тому, что обработчик исключений выдаст ошибку времени выполнения независимо от случая, если вы скомпилируете и запустите его в выпуске или отладке.

Только раз, когда вы не увидите ошибка возникает, когда вы используете операторы доступа к элементам [], как вы это делали в своем примере в режиме выпуска.

cout<<a[-2]<<endl;

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

По этой же причине рекомендуется использовать .at вместо прямого доступа к элементам с оператором [].

...