0

我有一个需要使用的带有灵活数组成员的结构。

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

这工作得很好。但是现在我需要一个对批量记录进行操作的接口,并且我一直在尝试为此使用 std::vector。然后问题开始出现,我猜这是因为 std::vector 将所有元素连续排列在内存上,并且由于 sizeof(Record) 不会考虑内容的大小(每个向量元素将只包含 4 个字节,而不是 4 字节 + size_of_contents * sizeof(Data)),向量元素实际上是共享内存,然后每个元素开始覆盖前一个元素的内容。那有意义吗?

如果这确实是问题所在,我想知道是否有任何方法可以“强制”向量为每个元素分配特定的大小(而不是 sizeof 返回元素类型的任何大小)。这样我可以确保每个向量元素都有足够的大小。如果这不可能,是否有替代解决方案?也许一个不同的容器可以让我这样做?请记住,我确实需要使用定义的结构(我很想将整个东西替换为向量,但不幸的是这是不可能的)

4

1 回答 1

2

你的主要问题是这样的:

myRecord = *(reinterpret_cast<Record*>(buffer.data());

这只是覆盖堆栈变量中的数据。那不改变myRecord突然指向的地址buffer.data()。这意味着当您稍后这样做时myRecord.contents[...] = ...,您将破坏堆栈。

您几乎可以肯定的意图是:

Record *myRecord = (reinterpret_cast<Record*>(buffer.data());

然后,您将有一个指向由 管理的内存的指针,该指针将为数组buffer提供足够的存储空间。myRecord->contents

不能将其视为Record值类型。就 C++ 的对象模型而言,它不是值类型。它不能像大多数 C++ 类型一样被复制或移动。您只能通过指向您在此处使用的特定分配的指针/引用来操作它。

话虽如此,像这样使用 avector来管理存储Record*真的很奇怪。最好使用 a unique_ptr,因为调整分配大小将是一个非常糟糕的主意。

std::unique_ptr<char[]> storage = new char[sizeof(Record) + (members.size() * sizeof(Data))];

这也可以防止系统初始化内存,因为无论如何你都要覆盖它。

我想知道是否有任何方法可以“强制”向量为每个元素分配特定的大小(而不是为元素类型返回任何 sizeof)。

No.vector管理同一类型的连续元素数组。而在 C++ 中,所有相同类型的对象都具有相同的大小。

于 2016-07-30T18:02:14.103 回答