Effective C++(17) 以獨立語句將newed對象置入智能指針

問題聚焦:
    使用了資源管理對象(如智能指針),就一定是安全的嗎?顯然不是。
    資源泄露發生可能在於,在“資源被創建”和“資源被轉換爲資源管理對象”兩個時間點之間有可能發生異常干擾。


看下面這個例子:
//函數說明
int priority();    //揭示處理程序的優先權
void processWidget(std::tr1::shared_ptr<Widget> pw, int priority);     // 用來在某動態分配所得的Widget上進行某些帶有優先權的處理
                                                                       // 這裏對動態分配得來的Widget運用智能指針
// 現在考慮調用processWidget
processWidget(new Widget, priority());        // 顯然編譯是不通過的,原因是類型不匹配。

// 如果像下面這樣調用即可
processWidget(std::tr1::shared_prt<Widget>(new Widget), priority());        // 編譯通過


然而令人驚訝的是,上述正確的調用方法,卻可能發生資源泄露
分析:
調用processWidget之前,編譯器需要做三件事:
  • 調用priority
  • 執行“new Widget”
  • 調用tr1:shared_ptr構造函數
問題在於:C++編譯器是以什麼樣的次序完成這些事情的呢?
答案是不確定的。
可以確定的是:“new Widget”一定執行於tr1::shared_ptr構造函數被調用之前。
但是對priority的調用則可以排在第一第二或第三的位置。
當priority的調用排在第二的位置時,執行次序如下:
  1. 執行“new Widget”
  2. 調用priority
  3. 調用tr1:shared_ptr構造函數
潛在的問題:如果第二步發生異常,new Widget返回的指針將會遺失。(其實爲什麼會遺失,這個問題有待驗證)
所以,資源泄露發生可能在於,在“資源被創建”和“資源被轉換爲資源管理對象”兩個時間點之間有可能發生異常干擾。


解決的方案:
使用分離語句
std::tr1::shared_ptr<Widget> pw(new Widget);
processWidget(pw, priority());
依據在於:編譯器對於“跨越語句的各項操作”沒有重新排列的自由。



小結:
以獨立語句將newed對象存儲於智能指針內,如果不這樣做,一旦異常被拋出,有可能導致難以察覺的資源泄漏。


參考資料:
《Effective C++ 3rd》

發佈了95 篇原創文章 · 獲贊 45 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章