看板 C_and_CPP 關於我們 聯絡資訊
最近想試著使用 std::shared_ptr 到新的程式碼中, 但是遇到一些 使用上的困擾, 尤其是 std::weak_ptr 的使用方式. 我有大略看過之前版友分享的影片, 可是對於 std::weak_ptr 的使 用依舊沒有具體概念. 先說明一下我對 std::shared_ptr 的使用認知: - #include <memory> - 使用 std::make_shared 建構 std::shared_ptr 以增進效率 - 建構 std::shared_ptr 的方式主要有二: + 接受一個『剛 new 出來』的裸指標 (建議使用 std::make_shared 替代) + 賦值為其他的 std::shared_ptr - std::shared_ptr 不應指向一個 new 出來的 C 風格陣列, 建議使 用 std::array 替代. 如果堅持要用 C 風格陣列的話要另外傳入 特製的陣列解構函式. - 需要在某類別內取得該類別物件的 std::shared_ptr 時,該類別 需繼承 std::enable_shared_from_this,之後我們可以用 shared_from_this 這個繼承的成員函式去取得。 - 避免使用 std::shared_ptr::get() 去獲得裸指標 - 使用 std::static_pointer_cast、std::dynamic_pointer_cast 及 std::const_pointer_cast 去對 std::shared_ptr 轉型 大致上 std::shared_ptr 的使用我覺得應該是蠻單純的. 但是在 std::weak_ptr 的使用方式上, 我目前的認知是: - #include <memory> - 從一個 std::weak_ptr 或 std::shared_ptr 建構 std::weak_ptr - std::weak_ptr 的使用時機: - 當我們對指標指向的物件之生命週期不需要有控制權的時候使用: + 可能只是想觀測指向同一物件的 std::shared_ptr 個數 + 可能邏輯上所指向的物件可以是存在或不存在的情況 - 當我們要解決 std::shared_ptr 的『循環參考』的問題時使用: 如果我們把所有的 std::shared_ptr 跟底層物件的指向關係畫 成一個圖. 則該圖需要是個 DAG (Directed acyclic graph), 否則會有記憶體洩漏 (memory leak) 的風險。 要將一個不是 DAG 的圖改成 DAG 的方式是利用 std::weak_ptr 去取代 std::shared_ptr 來解除圖中的循環 (cycle)。 只是要把哪些 std::shared_ptr 取代成 std::weak_ptr 是需要 設計過的. std::weak_ptr 所間接指向的物件必須不比 std::weak_ptr 本身 的生命週期短。否則 std::weak_ptr 可能會間接指向一個已經 死亡的物件,而無法取代原本 std::shared_ptr 的用途。 但是該間接參考的物件的死亡時間又是由指向該物件的所有 std::shared_ptr 所共同決定。 簡言之, 我們在將一個原有的圖改成 DAG 時,用 std::weak_ptr 所取代的 std::shared_ptr 所指向的物件,必須不能比該 std::weak_ptr 早死亡。也就是說指向該物件的 std::shared_ptr 中至少要有一個不會比該 std::weak_ptr 早死亡。 如何確保這件事情發生感覺有點複雜阿.... 我想到的三種解法: + 畫出圖後找到出現在循環中的所有物件,找出所有指向循環中的 物件而不在循環中的 std::shared_ptr 裡有最長生命週期的。 將循環中指向該物件的 std::shared_ptr 改為 std::weak_ptr + 額外產生一個最晚死亡的 std::shared_ptr 去指向某循環中的 物件。將循環中指向該物件的 std::shared_ptr 改為 std::weak_ptr。 + 在有可能出現循環的程式中放棄 std::shared_ptr 的使用 不曉得有沒有什麼方式讓我們容易判斷?或者是我認知上有什麼問 題嗎 Q_Q -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.112.29.148 ※ 編輯: Feis 來自: 140.112.29.148 (01/30 21:07)
azureblaze:weak_ptr可以指向已死物件 01/30 21:23
azureblaze:lock的時後會失敗得到nullptr 01/30 21:23
Feis:不. 我的意思是說使用方式. 如果用來解決 cycle 是不該已死的 01/30 21:29
Feis:例如你將 cycle 中全部 shared_ptr 改成 weak_ptr 後就無法用 01/30 21:29
Feis:如果沒有其他 shared_ptr 時 01/30 21:30
Feis:如果 weak_ptr 指向的物件在存在或不存在的情況下都合乎邏輯 01/30 21:31
Feis:那使用方式很單純. 只是在 cycle 時不一定是這樣 01/30 21:31
我加了一行字也許可以減少些誤會. ※ 編輯: Feis 來自: 140.112.29.148 (01/31 03:03)