C++11中引入了三種智能指針,分別是shared_ptr、weak_ptr和unique_ptr
智能指針的作用
智能指針可以幫助我們管理動態分配的堆內存,減少內存泄漏的可能性
手動管理堆內存有引起內存泄漏的可能,比如這段代碼
try {
int* p = new int;
// Do something
delete p;
} catch(...) {
// Catch exception
}
如果在執行Do something的時候發生了異常,那麼程序就會直接跳到catch語句捕獲異常,delete p這句代碼不會被執行,發生了內存泄漏
我們把上面的程序改成
try {
shared_ptr<int> p(new int);
// Do something
} catch(...) {
// Catch exception
}
當執行Do something的時候發生了異常,那麼try塊中的棧對象都會被析構。因此代碼中p的析構函數會被調用,引用計數從1變成0,通過new分配的堆內存被釋放,這樣就避免了內存泄漏的問題
循環引用問題
雖然智能指針會減少內存泄漏的可能性,但是如果使用智能指針的方式不對,一樣會造成內存泄漏。比較典型的情況是循環引用問題,比如這段代碼
class B; // 前置聲明
class A {
public:
shared_ptr<B> ptr;
};
class B {
public:
shared_ptr<A> ptr;
};
int main()
{
while(true) {
shared_ptr<A> pa(new A());
shared_ptr<B> pb(new B());
pa -> ptr = pb;
pb -> ptr = pa;
}
return 0;
}
這個程序中智能指針的引用情況如下圖
上圖中,class A和class B的對象各自被兩個智能指針管理,也就是A object和B object引用計數都爲2,爲什麼是2?
分析class A對象的引用情況,該對象被main函數中的pa和class B對象中的ptr管理,因此A object引用計數是2,B object同理。
在這種情況下,在main函數中一個while循環結束的時候,pa和pb的析構函數被調用,但是class A對象和class B對象仍然被一個智能指針管理,A object和B object引用計數變成1,於是這兩個對象的內存無法被釋放,造成內存泄漏,如下圖所示
解決方法
解決方法很簡單,把class A或者class B中的shared_ptr改成weak_ptr即可,由於weak_ptr不會增加shared_ptr的引用計數,所以A object和B object中有一個的引用計數爲1,在pa和pb析構時,會正確地釋放掉內存
————————————————