Я скомпилировал и запустил следующий код C ++, слепо пытаясь создать гибкий член массива, как вы можете в C:
#include <iostream>
template <typename T>
struct Vector {
int length;
T ts[];
};
Vector<int> ts = {
3,
{10, 10, 10},
};int main() {
std::cout << sizeof(ts) << std::endl;
std::cout << ts.data[1] << std::endl;
return 0;
}
Код компилируется и выполняется просто отлично, и выдает тот же вывод, что и C при тех же обстоятельствах (выводит 4, а затем 10).
Теперь согласно этот ответ от 2010 то, что я написал, не должно быть верным C ++. Кроме того, согласно эта статья в википедии, Msgstr «C ++ не имеет гибких членов массива».
Мой вопрос заключается в том, какую функцию C ++ я на самом деле использую в приведенном выше коде, особенно в строке, которая говорит:T ts[];
Msgstr «Этот код на самом деле делает то, что я думаю, он делает в целом, или это неопределенное поведение?
Это одна из тех вещей, которые отличаются между C и C ++. член гибкого массива допустимо в C, но не в C ++.
Тем не менее, многие современные компиляторы компилируют C как подмножество C ++, заботясь только о том, чтобы ускорить диагностику ошибок компилятора.
Дэвид Триббл тратит на это момент на своем Несовместимость между ISO C и ISO C ++ страница, где он конкретно решает эту проблему:
C ++ не поддерживает гибкие члены массива.
(Эта функция может быть предоставлена как расширение некоторыми компиляторами C ++, но, вероятно, будет действительной только для структурных типов POD.)
Так что да, это неопределенное поведение. Правильный способ (как на C, так и на C ++) написать такую вещь — дать ей ненулевое измерение:
template <typename T>
struct Vector {
int length;
T ts[1];
};
У вас есть другая проблема: вы должен выделить память для указанного объекта. Простого указания инициализатора недостаточно. Поскольку любой доступ к такой вещи существует, компилятор всегда думает, что это ее минимальный размер.
это «Дальний взлом» это так называется, потому что программист явно использует / использует способность C (и C ++) нарушать границы диапазона, чтобы сделать что-то хитрое.
Последствия этого многочисленны, в том числе невозможность хранить эти вещи в любом стандартном контейнере, передавать их по значению или делать все, что угодно, избегая обработки через указатель. Он имеет свое место, но для подавляющего большинства случаев использования C ++ имеет превосходные варианты.
Других решений пока нет …