第十一章:使用智慧指標管理物件資源

穆晨發表於2017-01-27

前言

       在前面的文章中,細緻地分析了建構函式,拷貝建構函式,賦值運算子,解構函式這幾個類中最重要函式的用法。

       如果嚴格地遵循這些做法,可以消除絕大部分資源管理的問題。

       然而,要想更靈活的使用物件中的資源,僅僅這些還不夠。譬如,若你想自己控制物件資源的生命週期(不要在作用域結束的時候自動被析構掉),那就應當好好考慮下智慧指標了。

       有人說,智慧指標是屬於設計模式範疇的產物,這麼說有點偏激,但也確實有點道理。

問題分析

       我們假定有一個投資類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可以完全取代動態分配而得到的陣列。

相關文章