是否可以有一个 std::vector 的结构和一个灵活的数组成员?
Is it possible to have a std::vector of struct with a fexible array member?
我有一个包含灵活数组成员的结构需要使用。
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)),向量元素实际上共享内存,然后每个元素开始覆盖前一个元素的内容。这有意义吗?
如果这确实是问题所在,我想知道是否有任何方法可以 "force" 向量为每个元素分配特定大小(而不是为元素类型分配任何 sizeof returns) .这样我就可以确保每个矢量元素都有足够的大小。如果那不可能,是否有替代解决方案?也许是一个不同的容器可以让我这样做?请记住,我 do 需要使用定义的结构(我很乐意将整个结构替换为向量,但不幸的是,这是不可能的)
你的主要问题是:
myRecord = *(reinterpret_cast<Record*>(buffer.data());
这只是覆盖堆栈变量中的数据。这不会将 myRecord
的地址更改为突然指向 buffer.data()
。这意味着当您稍后执行 myRecord.contents[...] = ...
时,您将破坏堆栈。
您几乎可以肯定的意图是:
Record *myRecord = (reinterpret_cast<Record*>(buffer.data());
然后你将有一个指向由 buffer
管理的内存的指针,它有足够的存储空间用于 myRecord->contents
数组。
您不能将Record
视为值类型。就C++的对象模型而言,它不是值类型。它不能像大多数 C++ 类型一样被复制或移动。你只能通过一个pointer/reference操作它到你在这里使用的特定分配。
也就是说,像这样使用 vector
来管理 Record*
的存储真的很奇怪。最好使用 unique_ptr
,因为调整分配大小将是一个非常糟糕的主意。
std::unique_ptr<char[]> storage = new char[sizeof(Record) + (members.size() * sizeof(Data))];
这也会阻止系统初始化内存,因为无论如何你都会覆盖它。
I was wondering if there's any way to "force" the vector to allocate a specific size for each element (instead of whatever sizeof returns for the element's type).
没有。 vector
管理相同类型元素的连续数组。而在 C++ 中,所有相同类型的对象都具有相同的大小。
我有一个包含灵活数组成员的结构需要使用。
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)),向量元素实际上共享内存,然后每个元素开始覆盖前一个元素的内容。这有意义吗?
如果这确实是问题所在,我想知道是否有任何方法可以 "force" 向量为每个元素分配特定大小(而不是为元素类型分配任何 sizeof returns) .这样我就可以确保每个矢量元素都有足够的大小。如果那不可能,是否有替代解决方案?也许是一个不同的容器可以让我这样做?请记住,我 do 需要使用定义的结构(我很乐意将整个结构替换为向量,但不幸的是,这是不可能的)
你的主要问题是:
myRecord = *(reinterpret_cast<Record*>(buffer.data());
这只是覆盖堆栈变量中的数据。这不会将 myRecord
的地址更改为突然指向 buffer.data()
。这意味着当您稍后执行 myRecord.contents[...] = ...
时,您将破坏堆栈。
您几乎可以肯定的意图是:
Record *myRecord = (reinterpret_cast<Record*>(buffer.data());
然后你将有一个指向由 buffer
管理的内存的指针,它有足够的存储空间用于 myRecord->contents
数组。
您不能将Record
视为值类型。就C++的对象模型而言,它不是值类型。它不能像大多数 C++ 类型一样被复制或移动。你只能通过一个pointer/reference操作它到你在这里使用的特定分配。
也就是说,像这样使用 vector
来管理 Record*
的存储真的很奇怪。最好使用 unique_ptr
,因为调整分配大小将是一个非常糟糕的主意。
std::unique_ptr<char[]> storage = new char[sizeof(Record) + (members.size() * sizeof(Data))];
这也会阻止系统初始化内存,因为无论如何你都会覆盖它。
I was wondering if there's any way to "force" the vector to allocate a specific size for each element (instead of whatever sizeof returns for the element's type).
没有。 vector
管理相同类型元素的连续数组。而在 C++ 中,所有相同类型的对象都具有相同的大小。