簡體   English   中英

在 std::vector 中存儲任意數據的方法<unsigned char>

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM