讀書筆記 effective c++ Item 17 使用單獨語句將new出來的對象放入智能指針。本站提示廣大學習愛好者:(讀書筆記 effective c++ Item 17 使用單獨語句將new出來的對象放入智能指針)文章只能為提供參考,不一定能成為您想要的結果。以下是讀書筆記 effective c++ Item 17 使用單獨語句將new出來的對象放入智能指針正文
假設我們有一個獲取進程優先權的函數,還有一個在動態分類的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,但是第一個參數包含兩部分:
在調用processWidget之前,編譯器必須為下面的三個步驟生成代碼:
對於上面三個步驟的執行順序,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出來的對象時要用單獨的語句,不然拋出異常的時候會發生微妙的資源洩漏。