假設(shè)我們有一個函數(shù)取得我們的處理優(yōu)先級,而第二個函數(shù)根據(jù)優(yōu)先級針對動態(tài)分配的 Widget 做一些處理:
int priority();
void processWidget(std::tr1::shared_ptr pw, int priority);
不要忘記使用對象管理資源的至理名言,processWidget 為處理動態(tài)分配的 Widget 使用了一個智能指針(在此,是一個 tr1::shared_ptr)。
現(xiàn)在考慮一個對 processWidget 的調(diào)用:
processWidget(new Widget, priority());
且慢,別想這樣調(diào)用。它不能編譯。tr1::shared_ptr 的構(gòu)造函數(shù)取得一個*指針(raw pointer)應(yīng)該是顯式的,所以不能從一個由 "new Widget" 返回的*指針隱式轉(zhuǎn)型到 processWidget 所需要的 tr1::shared_ptr。下面的代碼,無論如何,是可以編譯的:
processWidget(std::tr1::shared_ptr(new Widget), priority());
令人驚訝的是,盡管我們在這里各處都使用了對象管理資源,這個調(diào)用還是可能泄漏資源。下面就來說明這是如何發(fā)生的。
在編譯器能生成一個對 processWidget 的調(diào)用之前,它們必須傳遞實際參數(shù)來計算形式參數(shù)的值。第二個實際參數(shù)不過是對函數(shù) priority 的調(diào)用,但是第一個實際參數(shù)("std::tr1::shared_ptr(new Widget)"),由兩部分組成
·表達式 "new Widget" 的執(zhí)行。
·一個對 tr1::shared_ptr 的構(gòu)造函數(shù)的調(diào)用。
在 processWidget 能被調(diào)用之前,編譯器必須為這三件事情生成代碼:
·調(diào)用 priority。
·執(zhí)行 "new Widget"。
·調(diào)用 tr1::shared_ptr 的構(gòu)造函數(shù)。
C++ 編譯器允許在一個相當(dāng)大的范圍內(nèi)決定這三件事被完成的順序。(這里與 Java 和 C# 等語言的處理方式不同,那些語言里函數(shù)參數(shù)總是按照一個精確的順序被計算。)"new Widget" 表達式一定在 tr1::shared_ptr 的構(gòu)造函數(shù)能被調(diào)用之前執(zhí)行,因為這個表達式的結(jié)果要作為一個參數(shù)傳遞給 tr1::shared_ptr 的構(gòu)造函數(shù),但是 priority 的調(diào)用可以被第一個,第二個或第三個執(zhí)行。如果編譯器選擇第二個執(zhí)行它(大概這樣能使它們生成更有效率的代碼),我們最終得到這樣一個操作順序:
·執(zhí)行 "new Widget"。
·調(diào)用 priority。
·調(diào)用 tr1::shared_ptr 的構(gòu)造函數(shù)。
但是請考慮,如果對 priority 的調(diào)用引發(fā)一個異常將發(fā)生什么。在這種情況下,從 "new Widget" 返回的指針被丟失,因為它沒有被存入我們期望能阻止資源泄漏的 tr1::shared_ptr。由于一個異??赡懿迦胭Y源創(chuàng)建的時間和將資源交給一個資源管理對象的時間之間,所以調(diào)用 processWidget 可能會發(fā)生一次泄漏。 避免類似問題的方法很簡單:用一個單獨的語句創(chuàng)建 Widget 并將它存入一個智能指針,然后將這個智能指針傳遞給 processWidget:
std::tr1::shared_ptr pw(new Widget); // store newed object
// in a smart pointer in a
// standalone statement
processWidget(pw, priority()); // this call won’t leak
這樣做是因為編譯器在不同的語句之間重新安排操作順序的活動余地比在一個語句之內(nèi)要小得多。"new Widget" 表達式和 tr1::shared_ptr 的構(gòu)造函數(shù)的調(diào)用與 priority 的調(diào)用在不同的語句中,所以編譯器不會允許 priority 的調(diào)用插入它們中間。
Things to Remember
·在一個獨立的語句中將 new 出來的對象存入智能指針。如果疏忽了這一點,當(dāng)異常發(fā)生時,可能引起微妙的資源泄漏。
int priority();
void processWidget(std::tr1::shared_ptr
不要忘記使用對象管理資源的至理名言,processWidget 為處理動態(tài)分配的 Widget 使用了一個智能指針(在此,是一個 tr1::shared_ptr)。
現(xiàn)在考慮一個對 processWidget 的調(diào)用:
processWidget(new Widget, priority());
且慢,別想這樣調(diào)用。它不能編譯。tr1::shared_ptr 的構(gòu)造函數(shù)取得一個*指針(raw pointer)應(yīng)該是顯式的,所以不能從一個由 "new Widget" 返回的*指針隱式轉(zhuǎn)型到 processWidget 所需要的 tr1::shared_ptr。下面的代碼,無論如何,是可以編譯的:
processWidget(std::tr1::shared_ptr
令人驚訝的是,盡管我們在這里各處都使用了對象管理資源,這個調(diào)用還是可能泄漏資源。下面就來說明這是如何發(fā)生的。
在編譯器能生成一個對 processWidget 的調(diào)用之前,它們必須傳遞實際參數(shù)來計算形式參數(shù)的值。第二個實際參數(shù)不過是對函數(shù) priority 的調(diào)用,但是第一個實際參數(shù)("std::tr1::shared_ptr
·表達式 "new Widget" 的執(zhí)行。
·一個對 tr1::shared_ptr 的構(gòu)造函數(shù)的調(diào)用。
在 processWidget 能被調(diào)用之前,編譯器必須為這三件事情生成代碼:
·調(diào)用 priority。
·執(zhí)行 "new Widget"。
·調(diào)用 tr1::shared_ptr 的構(gòu)造函數(shù)。
C++ 編譯器允許在一個相當(dāng)大的范圍內(nèi)決定這三件事被完成的順序。(這里與 Java 和 C# 等語言的處理方式不同,那些語言里函數(shù)參數(shù)總是按照一個精確的順序被計算。)"new Widget" 表達式一定在 tr1::shared_ptr 的構(gòu)造函數(shù)能被調(diào)用之前執(zhí)行,因為這個表達式的結(jié)果要作為一個參數(shù)傳遞給 tr1::shared_ptr 的構(gòu)造函數(shù),但是 priority 的調(diào)用可以被第一個,第二個或第三個執(zhí)行。如果編譯器選擇第二個執(zhí)行它(大概這樣能使它們生成更有效率的代碼),我們最終得到這樣一個操作順序:
·執(zhí)行 "new Widget"。
·調(diào)用 priority。
·調(diào)用 tr1::shared_ptr 的構(gòu)造函數(shù)。
但是請考慮,如果對 priority 的調(diào)用引發(fā)一個異常將發(fā)生什么。在這種情況下,從 "new Widget" 返回的指針被丟失,因為它沒有被存入我們期望能阻止資源泄漏的 tr1::shared_ptr。由于一個異??赡懿迦胭Y源創(chuàng)建的時間和將資源交給一個資源管理對象的時間之間,所以調(diào)用 processWidget 可能會發(fā)生一次泄漏。 避免類似問題的方法很簡單:用一個單獨的語句創(chuàng)建 Widget 并將它存入一個智能指針,然后將這個智能指針傳遞給 processWidget:
std::tr1::shared_ptr
// in a smart pointer in a
// standalone statement
processWidget(pw, priority()); // this call won’t leak
這樣做是因為編譯器在不同的語句之間重新安排操作順序的活動余地比在一個語句之內(nèi)要小得多。"new Widget" 表達式和 tr1::shared_ptr 的構(gòu)造函數(shù)的調(diào)用與 priority 的調(diào)用在不同的語句中,所以編譯器不會允許 priority 的調(diào)用插入它們中間。
Things to Remember
·在一個獨立的語句中將 new 出來的對象存入智能指針。如果疏忽了這一點,當(dāng)異常發(fā)生時,可能引起微妙的資源泄漏。

