假設(shè)我們和一個投資(例如,股票,債券等)模型庫一起工作,各種各樣的投資形式從一個根類 Investment 派生出來:
class Investment { ... }; // root class of hierarchy of
// investment types
進(jìn)一步假設(shè)這個庫使用了通過一個 factory 函數(shù)為我們提供特定 Investment 對象的方法:
Investment* createInvestment(); // return ptr to dynamically allocated
// object in the Investment hierarchy;
// the caller must delete it
// (parameters omitted for simplicity)
通過注釋指出,當(dāng) createInvestment 函數(shù)返回的對象不再使用時,由 createInvestment 的調(diào)用者負(fù)責(zé)刪除它。那么,請考慮,寫一個函數(shù) f 來履行以下職責(zé):
void f()
{
Investment *pInv = createInvestment(); // call factory function
... // use pInv
delete pInv; // release object
}
這個看上去沒問題,但是有幾種情形會造成 f 在刪除它從 createInvestment 得到的 investment 對象時失敗。有可能在這個函數(shù)的 "..." 部分的某處有一個提前出現(xiàn)的 return 語句。如果這樣一個 return 執(zhí)行了,控制流程就再也無法到達(dá) delete 語句。還可能發(fā)生的一個類似情況是如果 createInvestment 的使用和刪除在一個循環(huán)里,而這個循環(huán)以一個 continue 或 goto 語句提前退出。還有,"..." 中的一些語句可能拋出一個異常。如果這樣,控制流程不會再到達(dá)那個 delete。無論那個 delete 被如何跳過,我們泄漏的不僅僅是容納 investment 對象的內(nèi)存,還包括那個對象持有的任何資源。
當(dāng)然,小心謹(jǐn)慎地編程能防止這各種錯誤,但考慮到這些代碼可能會隨著時間的流逝而發(fā)生變化。為了對軟件進(jìn)行維護,一些人可能會在沒有完全把握對這個函數(shù)的資源管理策略的其它部分的影響的情況下增加一個 return 或 continue 語句。尤有甚者,f 的 "..." 部分可能調(diào)用了一個從不慣于拋出異常的函數(shù),但是在它被“改良”后突然這樣做了。依賴于 f 總能到達(dá)它的 delete 語句根本靠不住。
為了確保 createInvestment 返回的資源總能被釋放,我們需要將那些資源放入一個類中,這個類的析構(gòu)函數(shù)在控制流程離開 f 的時候會自動釋放資源。實際上,這只是本文介紹的觀念的一半:將資源放到一個對象的內(nèi)部,我們可以依賴 C++ 的自動地調(diào)用析構(gòu)函數(shù)來確保資源被釋放。(過一會兒我們還要介紹本文觀念的另一半。)
許多資源都是動態(tài)分配到堆上的,并在一個單獨的塊或函數(shù)內(nèi)使用,而且應(yīng)該在控制流程離開那個塊或函數(shù)的時候釋放。標(biāo)準(zhǔn)庫的 auto_ptr 正是為這種情形量體裁衣的。auto_ptr 是一個類似指針的對象(一個智能指針),它的析構(gòu)函數(shù)自動在它指向的東西上調(diào)用 delete。下面就是如何使用 auto_ptr 來預(yù)防 f 的潛在的資源泄漏:
void f()
{
std::auto_ptr pInv(createInvestment()); // call factory
// function
... // use pInv as
// before
} // automatically
// delete pInv via
// auto_ptr’s dtor
class Investment { ... }; // root class of hierarchy of
// investment types
進(jìn)一步假設(shè)這個庫使用了通過一個 factory 函數(shù)為我們提供特定 Investment 對象的方法:
Investment* createInvestment(); // return ptr to dynamically allocated
// object in the Investment hierarchy;
// the caller must delete it
// (parameters omitted for simplicity)
通過注釋指出,當(dāng) createInvestment 函數(shù)返回的對象不再使用時,由 createInvestment 的調(diào)用者負(fù)責(zé)刪除它。那么,請考慮,寫一個函數(shù) f 來履行以下職責(zé):
void f()
{
Investment *pInv = createInvestment(); // call factory function
... // use pInv
delete pInv; // release object
}
這個看上去沒問題,但是有幾種情形會造成 f 在刪除它從 createInvestment 得到的 investment 對象時失敗。有可能在這個函數(shù)的 "..." 部分的某處有一個提前出現(xiàn)的 return 語句。如果這樣一個 return 執(zhí)行了,控制流程就再也無法到達(dá) delete 語句。還可能發(fā)生的一個類似情況是如果 createInvestment 的使用和刪除在一個循環(huán)里,而這個循環(huán)以一個 continue 或 goto 語句提前退出。還有,"..." 中的一些語句可能拋出一個異常。如果這樣,控制流程不會再到達(dá)那個 delete。無論那個 delete 被如何跳過,我們泄漏的不僅僅是容納 investment 對象的內(nèi)存,還包括那個對象持有的任何資源。
當(dāng)然,小心謹(jǐn)慎地編程能防止這各種錯誤,但考慮到這些代碼可能會隨著時間的流逝而發(fā)生變化。為了對軟件進(jìn)行維護,一些人可能會在沒有完全把握對這個函數(shù)的資源管理策略的其它部分的影響的情況下增加一個 return 或 continue 語句。尤有甚者,f 的 "..." 部分可能調(diào)用了一個從不慣于拋出異常的函數(shù),但是在它被“改良”后突然這樣做了。依賴于 f 總能到達(dá)它的 delete 語句根本靠不住。
為了確保 createInvestment 返回的資源總能被釋放,我們需要將那些資源放入一個類中,這個類的析構(gòu)函數(shù)在控制流程離開 f 的時候會自動釋放資源。實際上,這只是本文介紹的觀念的一半:將資源放到一個對象的內(nèi)部,我們可以依賴 C++ 的自動地調(diào)用析構(gòu)函數(shù)來確保資源被釋放。(過一會兒我們還要介紹本文觀念的另一半。)
許多資源都是動態(tài)分配到堆上的,并在一個單獨的塊或函數(shù)內(nèi)使用,而且應(yīng)該在控制流程離開那個塊或函數(shù)的時候釋放。標(biāo)準(zhǔn)庫的 auto_ptr 正是為這種情形量體裁衣的。auto_ptr 是一個類似指針的對象(一個智能指針),它的析構(gòu)函數(shù)自動在它指向的東西上調(diào)用 delete。下面就是如何使用 auto_ptr 來預(yù)防 f 的潛在的資源泄漏:
void f()
{
std::auto_ptr
// function
... // use pInv as
// before
} // automatically
// delete pInv via
// auto_ptr’s dtor