Возможно ли иметь std :: vector из struct с гибким членом массива?

У меня есть структура с гибким членом массива, который мне нужно использовать.

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, возвращаемого для типа элемента). Таким образом, я мог убедиться, что каждый элемент вектора будет иметь достаточный размер. Если это невозможно, есть ли альтернативное решение? Может быть, другой контейнер, который позволил бы мне сделать это? Пожалуйста, имейте в виду, что я делать нужно использовать структуру, как она определена (я хотел бы просто заменить все это на вектор, но, к сожалению, это невозможно)

0

Решение

Ваша принципиальная проблема заключается в следующем:

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 ++ все объекты одного типа имеют одинаковый размер.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]