簡體   English   中英

在資產管理器中高效使用c ++ 11 shared_ptr

[英]Efficient usage of a c++11 shared_ptr in an asset manager

我正在開發游戲(和我自己的自定義引擎)。 我有很多資產(紋理,骨骼動畫等)被多個模型使用,因此多次加載。

最初,我的野心更小,游戲更簡單,我可以進行一些重復,所以shared_ptr在最后一個實例消失后負責資源清理,這似乎是個好主意。 隨着我的游戲的發展,越來越多的資源被多次加載,並且所有OpenGL狀態的變化都會使性能下降到爬網的速度。 為了解決這個問題,我決定編寫一個資產管理器類。

我正在使用unordered_map將文件的路徑存儲在std::string和c ++ 11的shared_ptr指向實際加載的資產。 如果文件已被加載,則返回指針,否則,將調用相應的Loader類。 干凈利落。

不幸的是,我對刪除一無所知。 指針的一個副本保留在unordered_map 當前,我遍歷整個地圖並執行.unique()檢查每一幀。 那些原來是唯一的指針被從映射中刪除,破壞了最后一個副本,並迫使析構函數運行並進行清理。

遍歷成百上千個對象並不是最有效的方法。 (這不是過早的優化,我現在處於優化階段)是否可以以某種方式覆蓋共享指針功能? 例如,以某種方式添加“ onLastRemains”事件? 也許我應該每幀(按存儲桶)遍歷unordered_map一部分? 其他方式?

我知道,我可以嘗試編寫自己的引用計數資產實現,但是我擁有的所有當前代碼都假定資產是共享指針。 此外,共享指針在其工作方面非常出色,那么為什么要重新發明輪子呢?

而不是在資產管理器的map中存儲shared_ptr (請參見下文,使用常規地圖),而是存儲weak_ptr 構造新資產時,請使用自定義刪除器創建一個shared_ptr ,該刪除器將調用資產管理器中的一個函數,告訴該函數從其映射中刪除該指針。 定制刪除器應將該迭代器包含在該資產的映射中,並在告訴資產管理器從映射中刪除其元素時提供該迭代​​器。 在地圖中使用了weak_ptr的原因是,對該元素的所有后續請求仍可以被指定為shared_ptr (因為您可以從weak_ptr進行請求),但是資產管理器實際上並不擁有資產和自定義刪除器的所有權策略會奏效。

編輯:下面指出,上述技術僅在您使用std::map而不是std::unordered_map時才有效。 我的建議是仍然這樣做,並切換到常規地圖。

也許像這樣?

shared_ptr<assed> get_asset(string path) {
  static map<string, weak_ptr<asset>> cache;

  auto ap = cache[path].lock();
  if(!ap) cache[path] = ap = load_asset(path);
  return ap;
}

在資產的unordered_map中使用std::unique_ptr

使用自定義刪除器公開std::shared_ptr ,該刪除器在unordered_map中查找所述指針,然后刪除它,或將其移動到“稍后要刪除”的第二個容器中。 請記住, std::shared_ptr 具有實際擁有所涉及的數據! 刪除程序可以執行任何任意操作,甚至可以是有狀態的。

這樣一來,您就可以為資產進行O(1)查找,如果需要,可以進行大量清理(而不是在其他場景中間進行清理)。

您甚至可以支持臨時0參考計數,而無需刪除以下內容:

在資產的unordered_map中創建一個std::make_shared

公開自定義std::shared_ptr 它們在數據中保存原始T* ,而刪除器在資產映射中保存std::shared_ptr的副本。 它通過將名稱(它也持有)存儲到中央的“待刪除”列表中,從而“刪除”自己。

然后查看“待刪除”列表,檢查它們是否確實是unique() -如果不是,則表示在此期間其他人已生成“子” std::shared_ptr< T*, std::function<void(T*)>> s。

唯一的缺點是公開的std::shared_ptr的類型不再是簡單的std::shared_ptr

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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