[英]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.