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