所謂智能指針指的是一種用起來像指針但又無需關心內存管理的一種機制。程序員
C/C++中指針極爲常見,但普通指針最大的問題就在於須要程序員記住分配內存後要手動釋放,不然就會有內存泄漏或者引用野指針的風險。微信
好比有這樣一個簡單的類:函數
class person { public: person() {} ~person(){ cout<<"delete person."<<endl; } void display(){ cout<<"This is person"<<endl; } };
若是在堆上分配該對象的話,那麼在使用完後必須調用delete釋放內存:this
person* p = new person(); ... delete p; //使用完後手動釋放內存
那麼有沒有一種更好的機制來自動管理在堆上分配的對象呢?像下面這樣:spa
smart_pointer p(new person()); p->display(); // 無需手動調用delete釋放內存
答案是確定的。指針
指針本質上就是一個內存地址,所以普通指針根本就沒法分辨何時該指針指向的內存使用完畢,code
普通指針須要更聰明一點。對象
什麼狀況下一塊內存就能夠釋放掉了? 很簡單,沒人使用的時候就能夠釋放掉了。那麼該怎麼知道有沒有人在使用一塊內存?答案一樣很簡單,只須要記個數就能夠了。ip
不知道你們去遊樂園公園之類園區時有沒有注意過,這些地方一般會顯示園區裏如今有多少人,有人進去這個數字就加1,有人出來這個數字就減一,何時管理員就能夠關門了?固然是園區裏沒人的時候。內存
智能指針本質上就是園區裏顯示人數的指示牌,只不過在這裏不叫人數,而是叫引用計數,Reference counting。
普通指針自己並不能告訴咱們是否指向的內存還有沒有用,所以須要額外信息,這裏的額外信息就是引用計數,將引用計數和智能指針組合在一塊兒就是智能指針:
template<typename T> class smart_pointer { T* data; // 智能指針指向的內存 int count = 0; // 引用計數 };
建立智能指針時若是傳入的是內存地址,那麼咱們須要將引用計數設置爲1,由於這是智能指針首次指向某個內存地址,智能指針構造函數以下:
smart_pointer(T* per){ data = per; count = 1; }
固然智能指針的構造函數也能夠傳入另外一個智能指針,這時咱們必須在原有引用計數的基礎上加一,由於此時多了一個對該內存的引用,智能指針拷貝構造以下:
smart_pointer(const smart_pointer<T>& p){ data = p.data; count=p.count; ++count; }
當智能指針使用完畢被析構時就比如有人離開園區,這時必須判斷引用計數是否爲0,若是爲0那麼咱們應該關閉園區:
~smart_pointer(){ if ((--count) == 0) // 沒有人在園區了 delete data; }
固然,智能指針首先用起來必須和普通指針同樣,所以咱們須要重載指針的引用與解引用:
T& operator*(){ return *data; } T* operator->(){ return data; }
最後,不要忘了指針能夠被賦值,所以智能指針也應該支持賦值,這樣咱們須要重載賦值運算符。因爲指針被賦值後會指向新的內存,所以在智能指針指向新的內存前必須離開當前所在的園區:
smart_pointer<T> operator=(const smart_pointer<T>& p){ if(this == &p) return *this; // 是本身人 if ((--count) == 0) delete data; // 沒有人在這個園區了 data = p.data; // count = p.count; // 進到新園區 ++count; // return *this; }
簡單的使用一下剛剛發明的新指針 :)
void test_smartpointer(){ smart_pointer<person> p(new person("tom",30)); p->display(); smart_pointer<person> q = p; q->display(); smart_pointer<person> m(q); m->display(); }
一切工做正常。
但願這篇簡短的介紹能對你們理解智能指針有所幫助。固然,在真實項目中你們要使用C++標準定義的智能指針。
若是你喜歡這篇文章,歡迎關注微信公共帳號碼農的荒島求生獲取更多相關內容。
計算機內功決定程序員職業生涯高度