天天看點

智能指針——shared_ptr & weak_ptr

shared_ptr(引用計數) & weak_ptr

讓auto_ptr和scoped_ptr 很費腦子的一件事情就是:在拷貝構造和指派操作的時候,進行的是淺拷貝,就會在析構的時候對同一塊空間析構多次。

對于此問題,有一個很經典的解決辦法:引用計數!!!

在拷貝構造和指派運算符重載的時候,原指針 ap1 和 ap2 共享一個引用計數,對該引用計數進行++

在析構的時候,檢視引用計數是否為1,若為1,表示隻有目前指針使用這塊空間,可以對該指針進行釋放清理;

若大于1,表示還有其它指針在使用這塊空間,隻需要将引用計數進行 - -,不需要釋放這塊空間。

循環引用

由于引用計數和管理空間的對象的個數導緻空間不能釋放的結果就是循環引用。

智能指針——shared_ptr & weak_ptr

下面是對于shared_ptr和weak_ptr的簡單實作:

#include <iostream>
using namespace std;

template <class T>
class weak_ptr;

template <class T>
class shared_ptr
{
    friend class weak_ptr<T>;

public:
    shared_ptr(T* ptr)
        :_ptr(ptr)
        ,_refcount(new int(1))
    {
        cout<<"shared_ptr()"<<endl;
    }

    shared_ptr(const shared_ptr<T>& sp)
        :_ptr(sp._ptr)
        ,_refcount(sp._refcount)
    {
        (*_refcount)++;
    }

    shared_ptr<T>& operator=(const shared_ptr<T>& sp)
    {
        if(_ptr != sp._ptr)
        {
            if(--(*_refcount) == 0)         // 判斷該指針的這塊空間是否隻有它自己在使用,
            {
                delete _ptr;                // 如果是,則清理這塊空間(因為在調用指派之後,該指針與sp共享一塊空間,這塊空間就沒用了)
                delete _refcount;
            }

            _ptr = sp._ptr;                // 如果不是,直接指派(淺拷貝)
            _refcount = sp._refcount;
            (*_refcount)++;
        }
        return *this;
    }

    T& operator*()
    {
        return *_ptr;
    }

    T* operator->()
    {
        return _ptr;
    }

    int get_count()
    {
        return *_refcount;
    }

    ~shared_ptr()
    {
        if(--(*_refcount)  == 0)
        {
            delete _ptr;
            delete _refcount;
        }
        cout<<"~shared_ptr()"<<endl;
    }

private:
    T* _ptr;
    int* _refcount;
};

/
// shared_ptr 可能會有循環引用的問題
// 在可能出現循環引用的情況下,需要與weak_ptr搭配使用
template <class T>
class weak_ptr
{
public:
    weak_ptr(const shared_ptr<T>& sp)
        :_ptr(sp._ptr)
    {}

    T& operator*()
    {
        return *_ptr;
    }

    T* operator->()
    {
        return _ptr;
    }

private:
    T* _ptr;
};

struct ListNode
{
    int _data;
    weak_ptr<ListNode> _next;
    weak_ptr<ListNode> _prev;
    
    ListNode()
	    :_next(NULL)
	    ,_prev(NULL)
    {}
    
    // ~ListNode()
    // {
    //     cout<<"~ListNode()"<<endl;
    // }
};


int main()
{
    
    // shared_ptr

    // shared_ptr<int> sp1(new int(1));
    // *sp1 = 10;
    // cout<<"count:"<<sp1.get_count()<<endl;
    // // cout<<*sp1<<endl;
    //
    // shared_ptr<int> sp2(sp1);
    // cout<<"count:"<<sp1.get_count()<<endl;
    // shared_ptr<int> sp3(new int(1));

    // // cout<<*sp3<<endl;
    // sp3 = sp1;
    // // cout<<*sp3<<endl;
    // cout<<"count:"<<sp1.get_count()<<endl;
   

    
    // weak_ptr

    // weak_ptr<int> wp1(new int(1));
    shared_ptr<ListNode> l1(new ListNode);
    shared_ptr<ListNode> l2(new ListNode);
    cout<<l1.get_count()<<endl;
    cout<<l2.get_count()<<endl;

    l1->_next = l2;
    l2->_prev = l1;
    cout<<l1.get_count()<<endl;
    cout<<l2.get_count()<<endl;
    return 0;
}

           

繼續閱讀