C++智能指針循環引用問題

    今天遇到一個問題需要記錄一下,C++中的RAII機制對於內存泄漏問題有了很大的幫助。當我們在拿到一塊堆空間的時候,就應該用智能指針包裹起來,當對象生命週期結束的時候會自動釋放申請的內存。

    智能指針的類型常用的有三種,shared_ptr,unique_ptr,weak_ptr。三種智能指針各有特點,簡單而言,shared_ptr有引用計數,unique_ptr一個對象只能指向一塊給定內存(不支持拷貝和賦值),weak_ptr是一種“弱”智能指針,不控制對象的生命週期,也不增加引用計數。

    一般都是選擇shared_ptr,由於其引用計數功能,每當拷貝一個對象,引用計數就會增加1,同理,當一個shared_ptr對象銷燬時候,計數器就會減少1,當計數器爲0的時候,shared_ptr就會自動釋放其管理的對象。Shared_ptr簡單實現。

/*
 * @Description:  share_ptr的實現,注意不能用一個生指針給智能指針初始化(所以構造函數要聲明爲顯式)
 */
#ifndef _SHARE_PTR_H
#define _SHARE_PTR_H
#include <iostream>
#include <string>
template<typename T>
class My_Share_Ptr{
public:
    My_Share_Ptr():a(NULL),num(new int(0)){ }
    explicit My_Share_Ptr(T *ptr):a(ptr),num(new int(1)){ }
    My_Share_Ptr(const My_Share_Ptr& ptr):a(ptr.a),num(ptr.num)
    {
        (*num)++;//引用計數+1
    }
    My_Share_Ptr operator =(const My_Share_Ptr& ptr);
    ~My_Share_Ptr(){
        if(a && (*num)--){
            delete a;
            delete num;
        }
    }
public:
    T& operator*();

    T* operator->();

    inline T* get() const {
        return a;
    }
    inline int user_count() const{
        return *num;
    }
private:
    T *a;//內部指針
    int* num;//引用計數,注意這裏一定要指針
};


#endif
#include "share_ptr.h"

template<typename T>
My_Share_Ptr<T> My_Share_Ptr<T>::operator =(const My_Share_Ptr<T>& ptr){
    if(this==&ptr){
        return *this;
    }
    *num--;
    if(*num==0){
        delete num;
        delete a;
    }
    num=ptr.num;
    *num++;
    a=ptr->a;
    return *this;
}

template<typename T>
T& My_Share_Ptr<T>::operator *(){
    if(num==0){
        return (T*) 0;
    }
    return *a;
}

template<typename T>
T* My_Share_Ptr<T>::operator->(){
    if(num==0){
        return 0;
    }
    return a;
}

   接下來進入重點,最近在用shared_ptr的時候發現循環引用的問題,這裏需要注意一下。解決的方法就是在類中,用weak_ptr替代shared_ptr。

#include <iostream>
#include <memory>
using namespace std;
class TestA;
class TestB;
class TestA{
public:
    shared_ptr<TestB> ptr1;
public:
    TestA():ptr1(NULL){ }
};

class TestB{
public:
    shared_ptr<TestA> ptr2;
public:
    TestB():ptr2(NULL){ }
};

int main(){
    //以下四句會造成一個互相賦值的僵局(有點類似於死鎖,但是不是申請共享資源,而是形成一個鏈狀)
    shared_ptr<TestA> ptrA(new TestA);
    shared_ptr<TestB> ptrB(new TestB);
    ptrA->ptr1=ptrB;
    ptrB->ptr2=ptrA;
    
    return 0;
}

    無論ptrA還是ptrB,都會因爲引用計數沒有到達0,無法釋放在堆上的資源。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章