У меня есть структура с гибким членом массива, который мне нужно использовать.
struct Record
{
uint32_t length;
Data contents[];
};
Я могу инициализировать это и использовать его, выполнив что-то вроде этого: (это также будет работать с malloc или любым другим динамическим размещением)
vector<Data> members;
vector<uint8_t> buffer;
Record myRecord;
buffer.resize(sizeof(Record) + members.size() * sizeof(Data));
myRecord = *(reinterpret_cast<Record*>(buffer.data());
myRecord.length = static_cast<uint32_t>(members.size());
// copy members to myRecord.contents
Это работает просто отлично. Но теперь мне нужно иметь интерфейс, который работает с пакетами Record, и я пытался использовать для этого std :: vector. Тогда начинают появляться проблемы, и я предполагаю, что это потому, что std :: vector размещает все элементы непрерывно в памяти, а так как sizeof (Record) не будет учитывать размер содержимого (каждый элемент вектора будет содержать только 4 байта, вместо 4 байтов + size_of_contents * sizeof (Data)) векторные элементы фактически разделяют память, а затем каждый элемент начинает перезаписывать содержимое предыдущего элемента. Имеет ли это смысл?
Если это действительно проблема, мне было интересно, есть ли какой-либо способ «заставить» вектор выделять определенный размер для каждого элемента (вместо любого sizeof, возвращаемого для типа элемента). Таким образом, я мог убедиться, что каждый элемент вектора будет иметь достаточный размер. Если это невозможно, есть ли альтернативное решение? Может быть, другой контейнер, который позволил бы мне сделать это? Пожалуйста, имейте в виду, что я делать нужно использовать структуру, как она определена (я хотел бы просто заменить все это на вектор, но, к сожалению, это невозможно)
Ваша принципиальная проблема заключается в следующем:
myRecord = *(reinterpret_cast<Record*>(buffer.data());
Это просто перезаписывает данные в переменной стека. Это не меняет адрес myRecord
внезапно указать на buffer.data()
, Что означает, когда вы позже делаете myRecord.contents[...] = ...
ты собираешься разбить стек.
То, что вы почти наверняка намеревались, было:
Record *myRecord = (reinterpret_cast<Record*>(buffer.data());
Тогда у вас будет указатель на память, управляемую buffer
, который будет иметь достаточно места для хранения myRecord->contents
массив.
Вы не могу лечить Record
как тип значения. Что касается объектной модели C ++, то это не тип значения. Он не может быть скопирован или перемещен как большинство типов C ++. Вы можете манипулировать им только через указатель / ссылку на конкретное распределение, которое вы здесь используете.
Это, как говорится, используя vector
управлять хранилищем для вашего Record*
как это действительно странно. Было бы лучше использовать unique_ptr
Так как изменение размера выделения было бы действительно плохой идеей.
std::unique_ptr<char[]> storage = new char[sizeof(Record) + (members.size() * sizeof(Data))];
Это также не позволяет системе инициализировать память, так как вы все равно собираетесь ее перезаписать.
Мне было интересно, есть ли какой-нибудь способ «заставить» вектор выделять определенный размер для каждого элемента (вместо того, чтобы sizeof возвращал тип элемента).
Нет. vector
управляет непрерывным массивом элементов одного типа. А в C ++ все объекты одного типа имеют одинаковый размер.
Других решений пока нет …