Несоответствие в C ++ между выровненной структурой и перечислением внутри контейнера

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

Брошено, чтобы указать, что к массиву был обращен незаконный индекс. Индекс является либо отрицательным, либо большим или равным размеру массива.

Так, например:

int[] array = new int[5];
int boom = array[10]; // Throws the exception

Как избежать этого. ., не делайте этого. Будьте осторожны с вашими индексами массива.

Одной из проблем, с которыми иногда сталкиваются люди, является то, что массивы 1-индексируются, например

int[] array = new int[5];
// ... populate the array here ...
for (int index = 1; index <= array.length; index++)
{
    System.out.println(array[index]);
}

Это пропустит первый элемент (индекс 0 ) и выдают исключение, когда индекс равен 5. Действующие индексы здесь 0-4 включительно. Правильный, идиоматический оператор for здесь будет:

for (int index = 0; index < array.length; index++)

(Предполагается, что вы нуждаетесь в индексе, конечно. Если вы можете использовать расширенный для цикла, сделайте это.)

7
задан Jesper Juhl 25 June 2019 в 19:38
поделиться

3 ответа

Это проблема основной рабочей группы C ++ 2354 , которая недавно была решена путем удаления разрешения на применение alignas к типу enum. (На момент написания, последняя общедоступная версия списка проблем не содержит резолюции, но вы можете найти резолюцию в P1359R0 , который был принят в рабочий проект C ++ в феврале 2019 года и принят как отчет о дефектах (что означает, что исправление предназначено для применения задним числом).

Проблема в том, что у нас было два противоречивых требования:

  1. и перечисление base (включая неявное перечисление base of int в перечислении с областью действия) указывает базовый тип перечисления, и перечисление должно иметь такое же представление объекта (включая sizeof и представление всех значений) как его базовый тип, а

  2. и спецификатор выравнивания определяет выравнивание типа, которое, в свою очередь, также должно ограничивать sizeof(E) (которое по определению является расстоянием между двумя объектами типа E в массиве) до кратного указанного выравнивания.

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

Лучший совет - не применять спецификатор выравнивания к типу перечисления; реализации перестанут принимать это в какой-то момент. (Однако применение выравнивания к использованию типа в объявлении переменной или нестатического члена данных в порядке.)

6
ответ дан Richard Smith 25 June 2019 в 19:38
поделиться

Да, это похоже на ошибку.

В соответствии со стандартом - 9.11.2:

1 Спецификатор выравнивания может быть применен к переменной или к элементу данных класса, но не должен применяться к битовому полю. , параметр функции или объявление-исключение (13.3). Спецификатор выравнивания может также применяться к объявлению класса (в подробном спецификаторе типа (9.1.7.3) или заголовке класса (раздел 10), соответственно) и к объявлению перечисления (в непрозрачном enum-декларация или enum-head соответственно (9.6)). Спецификатор выравнивания с многоточием является расширением пакета (12.6.3).

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

UBSan также жалуется:

/usr/include/c++/8.3.0/ext/new_allocator.h:136: runtime error: store to misaligned address 0x602000000031 for type 'byte_enum', which requires 16 byte alignment
0x602000000031: note: pointer points here
 00 80 58  be be 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00
              ^ 
/usr/include/c++/8.3.0/bits/stl_iterator.h:797:17: runtime error: reference binding to misaligned address 0x602000000031 for type 'byte_enum', which requires 16 byte alignment
0x602000000031: note: pointer points here
 00 80 58  01 02 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00
              ^ 
/usr/include/c++/8.3.0/bits/stl_vector.h:1033:20: runtime error: reference binding to misaligned address 0x602000000031 for type 'value_type', which requires 16 byte alignment
0x602000000031: note: pointer points here
 00 80 58  01 02 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00
              ^ 
0x602000000050
0x602000000051
0x602000000052

Это может быть ошибкой libstdc ++ std::vector, потому что использование массива прекрасно работает с UBSan:

    {//with enum
        std::array<byte_enum, 3> bytes = { byte_enum{1}, byte_enum{2}, byte_enum{3} };
        for(auto it = bytes.begin(); it!= bytes.end(); ++it) {
                std::cout<<&*it<<std::endl;
        }
    }
2
ответ дан inf 25 June 2019 в 19:38
поделиться

Это не ответ, но дано:

std::cout << "16 structs: " << sizeof(byte_struct[16]) << std::endl;
std::cout << "16 enums:   " << sizeof(byte_enum  [16]) << std::endl;

clang печатает:

16 structs: 256
16 enums:   16

и gcc выдает ошибку:

error: alignment of array elements is greater than element size
  std::cout << "16 enums:   " << sizeof(byte_enum  [16]) << std::endl;
                                                      ^
1
ответ дан Marshall Clow 25 June 2019 в 19:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: