天天看點

C++解決智能指針交叉引用問題

智能指針的交叉引用問題,是如下代碼發生的問題,導緻的結果是對象無法析構,資源無法釋放,問題嚴重!

class B;
class A
{
public:
    A(){cout<<"A()"<<endl;}
    ~A(){cout<<"~A()"<<endl;}
    shared_ptr<B> _ptrb;
};

class B
{
public:
    B(){cout<<"B()"<<endl;}
    ~B(){cout<<"~B()"<<endl;}
    shared_ptr<A> _ptra;
};
int main(int argc, char* argv[])
{
    shared_ptr<A> ptra(new A());
    shared_ptr<B> ptrb(new B());

    ptra->_ptrb = ptrb;
    ptrb->_ptra = ptra;

    return ;
}
           

顯而易見,類A中有一個指向類B的shared_ptr強類型智能指針,類B中有一個指向類A的shared_ ptr強類型智能指針

此時,有兩個強智能指針指向了對象A,對象A的引用計數為2。也有兩個強智能指針指向了對象B,對象B的引用計數為2。對象A與對象B的關系如圖所示 :

C++解決智能指針交叉引用問題

當主函數return傳回後,對象A的引用計數減一變為1,對象B的引用計數減一變為1,此時因為引用計數不為0,是以不能析構對象釋放記憶體,程式結束造成記憶體洩漏。

解決方法:将類A和類B中的shared_ptr強智能指針都換成weak_ptr弱智能指針。我們在使用強弱智能指針的時候,有一個規定,就是建立對象的時候,持有它的強智能指針,當其他地方想使用這個對象的時候,應該持有該對象的弱智能指針。

class B;
class A
{
public:
    A(){cout<<"A()"<<endl;}
    ~A(){cout<<"~A()"<<endl;}
    weak_ptr<B> _ptrb; //其他地方持有對象的弱智能指針
};

class B
{
public:
    B(){cout<<"B()"<<endl;}
    ~B(){cout<<"~B()"<<endl;}
    weak_ptr<A> _ptra; //其他地方持有對象的弱智能指針
};

int main(int argc, char* argv[])
{
    shared_ptr<A> ptra(new A()); //建立對象時持有強智能指針
    shared_ptr<B> ptrb(new B()); //建立對象時持有強智能指針

    ptra->_ptrb = ptrb;
    ptrb->_ptra = ptra;

    return ;
}
           

weak_ptr弱智能指針,雖然有引用計數,但實際上它并不增加計數,而是隻觀察對象的引用計數,weak_ptr的引用計數指的是有多少個weak_ptr在觀察同一個shared_ptr。而shared_ptr強智能指針的引用計數是對資源的引用計數是以此時對象A的引用計數隻為1,對象B的引用計數也隻為1。此時對象A與對象B的關系如圖所示 :

C++解決智能指針交叉引用問題

當主函數return傳回後,對象A的引用計數減一變為0,是以正常析構對象A;對象B的引用計數減一變為0,是以正常析構對象B,此時不會造成記憶體洩漏。

總結:

(1)建立對象的時候用shared_ptr強智能指針,别的地方一律持有weak_ptr弱智能指針,否則析構順序有可能出現錯誤。

(2)當通過弱智能指針通路對象時,需要先進行lock提升操作,提升成功,證明對象還存在,再通過強智能指針通路對象。

參考:http://blog.csdn.net/qq_36953135/article/details/76998104

繼續閱讀