常用的資源有:記憶體、檔案描述器(file descriptor)、互斥鎖(mutex locks)、圖形介面中的字型和筆刷、資料庫連接、以及網路sockets。這些資源一般動態建立和分配,也就是一個指標。不論哪一種資源,重要的是,當你不再使用時,必須將它還給系統。
條款13:以對象管理資源
把資源放進對象裡,我們便可以依賴C++的 解構函式 自動調用機制,確保資源被釋放。對象在範圍結束時,其解構函式自動對其所指資源(對象)的指標調用delete。
C++提供了2種用於管理資源的類,“智能指標” std::auto_ptr,和 “引用計數型智能指標” std::tr1::shared_ptr。它們叫做智能指標,但本質是pointer-like對象,成員變數是表徵資源的指標。二者使用方法一樣:
1 class Investment { ... };
2 Investment* createInvestment();
3
4 void f()
5 {
6 ...
7 std::tr1::shared_ptr<Investment> pInv1(createInvestment());
8 // pInv1 points to the object returned from createInvestment
9 std::tr1::shared_ptr<Investment> pInv2(pInv1);
10 // both pInv1 and pInv2 now point to the object
11
12 pInv1 = pInv2; //OK
13 ...
14 }
auto_ptr不讓多個auto_ptr同時指向同一個對象。如果真的那樣,對象會被刪除一次以上,而那會導致“未定義行為”。為了預防這個問題,auto_ptr有一個不尋常的性質: 若通過copy建構函式或copy assignment操作符複製它們,它們會變成null,而複製所得的指標將取得資源的唯一擁有權。還記得嗎,STL容器要求其儲存的元素具有正常的複製行為,因此這些容器容不得auto_ptr。
shared_ptr具有正常的複製行為。可儲存於STL容器。
兩者在解構函式內都對資源指標執行delete,而不是delete[]。所以動態分配的數組用它們管理是個餿主意。vector和string幾乎總是可以取代動態分配得到的數組。
兩者有一個共同的名字,RAII對象。為防止資源流失,請使用RAII對象。它們在建構函式中獲得資源,並在解構函式中釋放資源。通常,我們選擇shared_ptr,因為其複製行為正常、直觀。而auto_ptr複製動作會使他指向NULL。
兩外,tr1::shared_ptr 允許當智能指標被建立起來時制定一個資源釋放函數(所謂刪除器,"deleter")綁定於智能指標身上(auto_ptr 就沒有這個能耐)。當引用次數為0時候,刪除器 被調用。
tr1::shared_ptr 支援定製型刪除器。可以被用於自動解除互斥鎖(mutexes, 見條款14)等等。
條款17:以獨立語句將newed 對象置入智能指標
1 processWidget(std::tr1::shared_ptr<Widget>(new Widget), priority()); //非獨立語句
2 std::tr1::shared_ptr<Widget> pw(new Widget); //獨立語句
3 processWidget(pw, priority());
1行中,編譯器要執行三個操作。其中兩個參數的計算次序編譯器先做什麼是有彈性的。如果如果priority函數在new之後執行,並且函數出現異常,新產生的Widget對象將未置入智能指標,資源產生泄漏。2、3行則解決了這個問題。