智慧型指標是 C++ 中一個常用的設計模式,它可以讓 C++ 的程式自行管理記憶體的配置與回收,避免記憶體洩漏等問題。
在 C/C++ 語言中,我們常常會使用指標(pointer)來配置或存取記憶體,一個指標變數儲存了記憶體的位址,而程式設計師就可以運用這個記憶體位址來做出各種變化,是一個非常好用的型別,甚至在某些複雜的應用上,如果沒有指標這項功能的話,可能會讓程式設計師不知道如何開發程式。
雖然指標對於 C/C++ 程式設計師而言非常重要,不過它難以管理的問題,也常常讓程式開發者頭痛,如果記憶體沒有配置得當,很容易造成懸置指標(dangling pointer)、空指標例外(null pointer exception)與記憶體洩漏(memory leak)等問題,嚴重的話會讓直接讓整個程式當掉、無法執行,而且記憶體配置與指標的問題在除錯上比較麻煩,編譯器並不會因為存取不對的記憶體位址而發出警告,必須要靠程式設計師自己小心的來處理。
Foo* foo = new Foo(); foo->Study(); // 如果這裡發生例外(exception)的話, delete foo; // 最後的記憶體將無法回收
如果在 Study()
函數中發生例外,讓程式提早跳出原有的執行順序的話,有可能就會造成這裡配置的記憶體永遠無法回收,直到程式執行結束為止,而這樣的問題就可以考慮以智慧型指標來解決。
智慧型指標其實就是把一般的指標包裝在 C++ 的物件之中,然後再加上一些記憶體管理的功能,而在使用上則跟一般的指標差不多,所以可以直接用來代替一般的指標。
智慧型指標的實作方式有許多種,這裡我們只是示範其中一種比較簡單的方式。其最基本的概念就是實作一個類別,將 *
與 ->
這兩個運算子多載化(overloading),並在解構子(destructor)中加入記憶體回收的功能。
#include<iostream> class Ptr { // 實作智慧型指標的類別 int *ptr; public: explicit Ptr(int *p = NULL) { ptr = p; } // 將指標儲存起來 ~Ptr() { delete(ptr); } // 回收記憶體 int &operator *() { return *ptr; } // 多載化 * 運算子 }; int main() { Ptr ptr(new int()); *ptr = 4; cout << *ptr; // 智慧型指標會自動回收記憶體 return 0; }
這裏我們使用智慧型指標來管理記憶體,在動態配置的記憶體使用完之後,它就會自動回收沒有用的記憶體。這裡我們以基本的 int*
指標來示範實作的概念,實務上通常我們會改用泛型程式設計的方式,實作各種型別都可以用的智慧型指標。
由於智慧型指標已經是一個很普遍的技術了,有許多開放原始碼的函式庫都有提供這樣的功能,與其自己寫倒不如直接使用既有的函式庫,例如 boost 就有提供這樣的功能,另外在 C++ 11 的標準中也加入了 General-purpose smart pointers,所以如果現在要開發新的程式,直接使用這些資源會比較輕鬆。
參考資料:The Geek Stuff