c++11中引入了之前在boost庫中的智能指針,智能指針有三種shared_ptr, weak_ptr, unique_ptr。
引入智能指針的作用是為了保證在出現異常時,也能保證堆內存會被釋放掉,如下面代碼:
void fun() { T *t = new T(); //do something delete t; return; }
在do something的時候,如果出現了異常或者其他原因,導致提前結束離開函數,那么new出來的內存將不會被釋放。而使用智能指針管理這塊內存時,會通常會在智能指針本身被析構時,正確的釋放這個new出來的內存。
其中shared_ptr用於共享某一塊內存,shared_ptr維護了一個足夠大的引用計數,保證在引用計數歸0時正確的釋放掉堆中的內存,但是僅僅使用shared_ptr是不夠的,如下面的代碼:
class B; class A { public: shared_ptr<B> p; }; class B { public: shared_ptr<A> p; }; int main() { while (true) { shared_ptr<A> pa(new A()); shared_ptr<B> pb(new B()); pa->p = pb; pb->p = pa; } return 0; }
在while循環中,先是在棧中構造了兩個智能指針,分別管理兩塊堆內存,記為A, B。然后兩個賦值語句,使得在shared_ptr中,A,B的引用計數均為2,所以在析構掉pa與pb時,他們的引用計數都沒能到達0,於是發生了循環引用,於是開始內存泄露,用不了多久內存爆炸程序死掉,運氣不好還會死機> , <
解決方案也很簡單,將類A,B中的一個shared_prt改為weak_ptr即可,weak_ptr不會增加shared_ptr的引用計數,所以在pa,pb中會有一個的引用計數為1,在它析構時,會正確的釋放掉內存。
所以shared_ptr是用來共享內存,而weak_ptr是用來避免循環引用的。 使用weak_ptr時需要用lock檢查weak_ptr保存的指針是否有效。
此外unique_ptr是一種特殊的shared_ptr,它的拷貝構造函數以及拷貝運算符是刪除的,這意味着當我們這樣初始化一個unique_ptr時,它會獨占內存:
unique_ptr up(new T());
我們丟失了原生指針,而且unique_ptr不能復制,當然如果非得作死這么寫也是不會報錯的:
T *p = new T();
unique_ptr up1(p);
unique_ptr up2(p);
這樣兩個unique_ptr有了同樣的原生指針- -!但是這么寫毫無意義。
值得注意的是unique_ptr雖然不支持拷貝,但是是支持移動的,所以它通常這么用:
unique_ptr<int> fun() { unique_ptr<int> up(new int(999)); return up; } int main() { unique_ptr<int> up = fun(); return 0; }
保證指針唯一的情況下,還能傳遞內存的所有權。