前言
在前面的文章中,細緻地分析了建構函式,拷貝建構函式,賦值運算子,解構函式這幾個類中最重要函式的用法。
如果嚴格地遵循這些做法,可以消除絕大部分資源管理的問題。
然而,要想更靈活的使用物件中的資源,僅僅這些還不夠。譬如,若你想自己控制物件資源的生命週期(不要在作用域結束的時候自動被析構掉),那就應當好好考慮下智慧指標了。
有人說,智慧指標是屬於設計模式範疇的產物,這麼說有點偏激,但也確實有點道理。
問題分析
我們假定有一個投資類Investment:
1 class Investment 2 { 3 // ...... 4 };
很多其他的投資型別都由這個類派生出來,比如股票投資,基金投資等等。
進一步假設,有某個工廠函式專門供應特定的Investment物件:
1 Investment * createInvestment();
必須說明的是,這個函式是通過new來在堆中建立物件的,因此,函式結束後,資源並不會釋放掉,而是需要呼叫這個函式的使用者來手工釋放掉,如下所示:
1 void f() 2 { 3 // ...... 4 Investment * pInv = createInvestment(); 5 // ...... 6 delete pInv; 7 // ...... 8 }
下面問題來了:如果在 4 - 6行之間有 continue 或者 goto 或者其他中斷程式執行的語句,那麼將會導致 delete 無法執行,從而記憶體洩露。
這種情況下,使用者肯定是想 pInv 在作用域結束的時候就會自動地釋放掉,好在智慧指標能解決這個問題。
智慧指標介紹
智慧指標的本質其實是一個能夠幫使用者管理資源的類指標物件。
許多資源被動態分配於heap後被用於單一區塊或函式內,智慧指標可以讓資源在離開控制流的時候得到釋放。
應用得比較多的有auto_ptr和shared_ptr兩種智慧指標。
前者管理的資源必須是一個智慧指標所指向的。當前者進行賦值的時候,會將賦值運算子右值的智慧指標變成NULL,而其左值獲得右邊指標原來指向的資源。
後者管理的資源則未必,它允許多個智慧指標指向同一份資源,同時會統計資源被指的個數,只有指向該資源的智慧指標都離開了作用域,才會正式析構掉資源。
智慧指標的使用:
1 void f() 2 { 3 // ...... 4 std::auto_ptr<Investment>pInv(createInvestment()); 5 std::shared_ptr<Investment>pInv(createInvestment()); 6 // ...... 7 }
在構造好了智慧指標之後,便可以不用理會該資源回收的事,智慧指標將會幫你打理!
如果要通過智慧指標獲得原始資源指標,則呼叫智慧指標的 .get() 即可,而如果要訪問原始資源,智慧指標過載了->和*()操作符,使用起來和原始指標一樣。
另外,智慧指標shared_ptr還可以自定義刪除器,指定刪除物件時(指向資源的指標數為0)要做的具體事情(不一定是銷燬資源)。
由於智慧指標的型別很多,使用方法也五花八門,這裡就不一一介紹了,請參考相關的使用手冊。
小結
1. 當你需要提前實現多型的話,請new一個子類並將結果返回給一個父類指標。
2. 智慧指標不支援內建型別,那是因為C++認為Vector可以完全取代動態分配而得到的陣列。