智能指針與循環引用


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;
}

保證指針唯一的情況下,還能傳遞內存的所有權。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM