1. 可能會出現資源洩漏的一種用法
假設我們有一個擷取程序優先權的函數,還有一個在動态配置設定的Widget對象上根據程序優先權進行一些操作的函數:
1 int priority();
2
3 void processWidget(std::tr1::shared_ptr<Widget> pw, int priority);
注意這裡使用了對象管理資源的用法(
Item 13),processWidget為它需要處理的動态配置設定對象Widget使用了智能指針(tr1::shared_ptr)。
現在考慮對processWidget函數的調用:
1 processWidget(new Widget, priority());
這個函數調用不能通過編譯,因為在tr1::shared_ptr構造函數中顯示的使用了一個原生指針,而不能将“new Widget”傳回的原生指針直接隐式轉換為tr1::shared_ptr。下面的代碼将會通過編譯:
1 processWidget(std::tr1::shared_ptr<Widget>(new Widget), priority());
雖然這裡我們使用了對象類管理資源,但是這個調用仍然可能出現記憶體洩漏。如何才能出現資源洩漏呢?
2. 在什麼情況下會出現資源洩漏?
在編譯器生成一個對processWidget的調用之前,它們必須對函數參數做一些檢查。第二個參數隻是調用了函數priority,但是第一個參數包含兩部分:
- New Widget的執行
- 對tr1::shared_ptr構造函數的調用
在調用processWidget之前,編譯器必須為下面的三個步驟生成代碼:
- 調用priority
- 執行 “new Widget”
- 調用tr1::shared_ptr構造函數。
對于上面三個步驟的執行順序,c++編譯器被給予了相當大的自由。(這同java和c#不同,這兩門語言的執行順序固定)“new Widget”表達式必須在tr1::shared_ptr構造函數之前被調用,因為它的結果會傳遞給tr1::shared_ptr作為參數,但是對priority()函數的執行次序是任意的(第一個,第二個,第三個執行都可以)。如果編譯器選擇第二個執行(因為這樣可能會生成更高效的代碼),執行順序如下:
如果調用priority時産生異常将會發生什麼?在這種情況下,從”new Widget”傳回的指針會被丢失,因為它沒有存入tr1::shared_ptr中,但我們的原意是使用tr1::shared_ptr來防止資源洩漏。對processWidget的調用會使資源洩漏發生,因為在資源被建立和将資源轉交給資源管理對象的時間間隔内插入了異常。
3. 如何避免資源洩漏
防止這個問題的方法比較簡單:使用一個單獨的句子建立Widget并将其存入智能指針,然後将智能指針傳入processWidget:
1 std::tr1::shared_ptr<Widget> pw(new Widget); // store newed object
2
3 // in a smart pointer in a
4
5 // standalone statement
6
7 processWidget(pw, priority()); // this call won’t leak
這種方法是行得通的,編譯器被給予更少的餘地來對語句進行重新排序。在上面的代碼中,我們将“new Widget”以及對tr1::shared_ptr構造函數的調用放在一個語句中,把對priority的調用放在另一個語句中,這樣就不允許編譯器在”new Priority”和tr1::shared_ptr構造函數之間執行priority。
4. 總結
在智能指針中存儲new出來的對象時要用單獨的語句,不然抛出異常的時候會發生微妙的資源洩漏。
作者:
HarlanC部落格位址:
http://www.cnblogs.com/harlanc/個人部落格:
http://www.harlancn.me/本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出,
原文連結如果覺的部落客寫的可以,收到您的贊會是很大的動力,如果您覺的不好,您可以投反對票,但麻煩您留言寫下問題在哪裡,這樣才能共同進步。謝謝!