參考自《effective morden c++》
裸指針的缺點
- 無法知道指向的是單個對象還是一個數組.
- 無法知道使用完之後是否需要析構,即是否擁有指向的對象.
- 無法知道應當如何析構(使用 delete 還是專門的函數)
- 無法知道單個析構還是數組析構.
- 不能保證只析構一次。少了會導致內存泄漏,多了是UB.
- 無法檢查指針空懸.
std::unique_ptr
- 足夠小、足夠快,幾乎和裸指針相同.
- 是一個只移類型(不可複製),當其析構時,內部的對象也會被析構。
- 可以自定義刪除器,會略微增大尺寸.
- 自定義刪除器的類型需要加入到模板參數中
- 不建議用其存儲數組,可以使用 vector, array 等.
- 可以方便地轉爲 shared_ptr.
std::shared_ptr
- 尺寸是裸指針的兩倍,因爲內部既包含一個資源指針,又包含一個控制塊的指針.
- 引用計數是原子性的.
- 自定義刪除器不需要加入到模板參數.
- 控制塊包括:引用計數、弱計數、其他數據(自定義刪除器等)
- 不要用保存好的裸指針來創建 shared_ptr,直接從 new 創建。因爲會創建一個新控制塊.
- 由上,從 this 創建指針也是很危險的,可以讓類 T 繼承
std::enable_shared_from_this<T>
,然後使用 shared_from_this 函數創建.
這裏的設計模式叫 奇異遞歸模板模式. - 不要用它保存數組
std::wake_ptr
- 用於 sp 的輔助,不能直接獲取指向的資源.
- expired() 判斷是否失效.
- 如果需要線程安全地判斷是否失效並且沒失效時返回一個 shared_ptr,可以使用
- lock(),如果失效返回的 sp 爲空
- 直接創建,如果失效會返回異常.
- 用途:緩存觀察是否失效,觀察者模式,避免 sp 循環依賴.
- 控制塊裏的弱計數記錄 wp 的數量,當 sp 和 wp 數量全部爲0後,控制塊纔會被析構。
std::make_unique, std::make_shared
- make_unique 是 C++ 14的部分,可以自己寫一個(暫略)
- 優先使用 make_shared,因爲速度更快:控制塊和託管對象處在同一內存區域。
- 不適用的情況包括:自定義刪除器,直接傳遞大括號初始化。
- 使用 make_shared 後,如果 sp 數量已經爲0,但還有 wp,那麼內存不會被釋放(對象已經被析構,控制塊未被析構).