Item 13:Use objects to manage resources
假設我們使用一個用來塑膜投資行爲的程序庫,其中各式各樣的投資類型繼承自一個root class:
class Investment { ... }; //“投資類型”繼承體系中的root class
進一步假設,這個程序系通過一個工廠函數(工廠函數會“返回一個base class指針,指向新生成的derived class 對象),供應我們某特定的Investment對象:
Investment* createInvestment( );
createInvestment的調用端使用了函數返回的對象後,有責任將其刪除。現在考慮有個f函數履行了這個責任:
void f()
{
Investment* pInv = createInvestment(); //調用factory函數
...
delete pInv; //釋放pInv所指對象
}
這看起來妥當,但若干情況下f可能無法刪除它得自createInvestment的投資對象——或許因爲”。。。“區域內的一個過早的return語句,又或者這個delete語句可能位於某循環內,而該循環由於某個continue或goto語句過早退出。無論delete如何被略過去,我們泄漏的不只是內含投資對象的那塊內存,還包括那些投資對象所保存的任何資源。
而且一旦軟件開始接受維護,可能會有人添加return語句或continue語句而未能全然領悟它對函數的資源管理策略造成的後果。因此單純依賴”f總是會執行其delete語句是行不通的“。
爲了解決這個問題,作者推薦了auto_ptr和shared_ptr兩種智能指針。
auto_ptr是個”類指針對象“,其析構函數自動對其所指對象調用delete。下面師範如何使用:
void f()
{
std::auto_ptr<Investment> pInv(createInvestment());
//調用factory函數
...
} //經由auto_ptr的析構函數自動刪除pInv
所謂“以對象管理資源”的觀念常被稱爲“資源取得時機便是初始化時機”(即RAII),因爲我們幾乎總是在獲得一筆資源後於同一語句內以它初始化某個管理對象。
//雲風評註:使用auto_ptr時一定要小心。它解決的是在棧堆上使用指針引用一個對象後的安全釋放問題。多個auto_ptr不能共享同一對象的所有權,也不能通過它引用一個對象數組等。auto_ptr有諸多問題,現在已經不推薦使用。在新的標準中,建議使用unique_ptr.//
auto_ptr有一個不同尋常的性質:若通過copy構造函數或copy assignment操作符複製它們,它們會變成NULL,而複製所得的指針將取得資源的唯一擁有權。
std::auto_ptr<Investment> pInv1(createInvestment());
std::auto_ptr<Investment> pInv2(pInv1);//現在pinv2指向對象,pInv1被設爲NULL
pInv1 = pInv2; //現在pInv1指向對象,pInv2被設爲NULL
最後,auto_ptr和tr1::shared_ptr兩者都在其析構函數內做delete而不是delete[]動作。那意味在動態分配而得的array身上使用auto_ptr或tr1::shared_ptr是個餿主意。可嘆的是,那麼做仍能通過編譯。
std::auto_ptr<std::string> aps(new std::string[10]);
std::tr1::shared_ptr<int> spi(new int[1024]);
std::tr1::shared_ptr<int> spi(new int[1024]);
這兩種方式都會用上錯誤的delete形式。
//雲風評註:[ ]和vector是C++混亂的根源之一。如果你決定使用STL或template風格的C++,那麼儘可能避免使用[ ],而不要去糾結哪個效率更高。
請注意:
爲防止資源泄漏,請使用RAII對象,它們在構造函數中獲得資源並在析構函數中釋放資源。