[英]Ways to store arbitrary data in a std::vector<unsigned char>
我有一个第三方 api,它提供以下类型(大约)用于将任意数据附加到树结构中的节点:
// 3rd party, cannot be modified
struct AttachedData
{
std::string key;
std::vector<unsigned char> data;
};
我认为它使用std::vector<unsigned char>
因为数据也可以写入磁盘,但这在我的用例中并不重要,因为数据仅在运行时保留。
有不同类型的对象必须存储在AttachedData
(每个实例只有一个对象)。 因为我只在运行时需要数据,所以我没有费心实现任何类型的序列化(主要是因为不必要的开销)。 我决定使用所有可能类型的变体,并在AttachedData
存储指向其实例的指针:
using StorageType = std::variant<EventArgs1, EventArgs2, SomeData /*, ...*/>;
AttachedData& attachedData = api.getAttachedData(targetNode, "some key"); // get the correct container
auto storage = new StorageType(someDataInstance); // somehow create the variant on the heap
attachedData.data.resize(sizeof(storage)); // make enough space
std::memcpy(attachedData.data.data(), &storage, sizeof(storage)); // store the pointer to the variant
在代码库的不同位置读取和处理数据:
AttachedData& attachedData = api.getAttachedData(targetNode, "some key"); // get the correct container
StorageType* storage = nullptr;
std::memcpy(&storage, attachedData.data.data(), sizeof(storage)); // read the pointer
// process the stored data
if (auto* args1 = get_if<EventArgs1>(storage))
// ...
else if (auto* args2 = get_if<EventArgs2>(storage))
// ...
// ...
// clean up
attachedData.data.clear();
delete storage;
有没有更干净或更优雅的方法来做到这一点? 我还考虑过使用placement new 并直接在向量中构建变体,但这可能会导致对齐问题,而且我也看不到任何好处。 我认为std::variant
是一个很好的方法,但我也愿意接受这方面的建议。
更新
此答案中提出的方法不适用于 OP,因为事实证明,存储在节点中的向量可能会在没有用户控制的情况下被复制、移动或破坏。 我暂时不会删除答案,因为下面的讨论澄清了一些重要的细节,可能对其他人有用。
原答案
我不知道我是否理解这个问题,但是您可以在向量中创建一个StorageType
对象(即std::variant
)。 你只需要调整向量的大小以适应里面的对象:
AttachedData& attachedData = api.getAttachedData(targetNode, "some key");
attachedData.data.resize(sizeof(StorageType));
StorageType* p_obj = new (attachedData.data.data()) StorageType{someDataInstance};
只要所有变体的替代方案都没有过度对齐,对齐应该没问题。
然后,在后面的代码中,您可以获得对存储对象的访问权限,如下所示:
AttachedData& attachedData = api.getAttachedData(targetNode, "some key"); // get the correct container
StorageType* p_obj = std::launder(reinterpret_cast<StorageType*>(attachedData.data.data()));
请注意,您需要在某处通过调用析构函数手动销毁所有存储的对象,或者使用std::destroy_at
更好。
至于你的尝试,它有几个问题。 例如,您不能将memcpy
用于非平凡可复制类型的对象,或者您正在使用&storage
,它是指向内存中storage
指针存储位置的指针(而不是它指向的指针)。
更新
根据您在评论中指定的其他详细信息,此方法将不起作用,因为您无法控制矢量的复制、移动或破坏。 在这种情况下,没有任何方法可以正常工作。 一旦你在向量中创建了一个对象,它的复制/移动/销毁将不会正确地涉及存储在其中的对象的复制/移动/销毁。 您的变体替代品是否可以轻松复制?
请注意,即使所有替代项都是, std::variant
本身也不能保证在 C++17 中可以简单地复制。 有一个针对这个问题的建议。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.