智能指針的模擬實現

1.引入

int main()
{
    int *p = new int;   //裸指針
    delete p;
    return 0;
}

在上面的代碼中定義了一個裸指針p,需要我們手動釋放。如果我們一不小心忘記釋放這個指針或者在釋放這個指針之前,發生一些異常,會造成嚴重的後果(內存泄露)。而智能指針也致力於解決這種問題,使程序員專注於指針的使用而把內存管理交給智能指針。
普通指針也容易出現指針懸掛問題,當有多個指針指向同一個對象的時候,如果某一個指針delete了這個對象,所以這個指針不會對這個對象進行操作,那麼其他指向這個對象的指針呢?還在等待已經被刪除的基礎對象並隨時準備對它進行操作。於是懸垂指針就形成了,程序崩潰也“指日可待”。

int main()
{
    int *p1 = new int(2);
    int *p2 = p1;
    int *p3 = p2;
    cout<<*p1<<endl;
    cout<<*p2<<endl;
    cout<<*p3<<endl;
    delete p1;
    cout<<*p2<<endl;
    return 0;
}

輸出結果

2
2
2
-572662307

輸出的結果*p2的結果並不是期待中2,因爲2早已經被刪除了。
這裏寫圖片描述
這裏寫圖片描述

  1. 智能指針
    智能指針是一個類,它把普通指針封裝起來,能實現和普通指針同樣的功能。不同的是智能指針能夠對內存進行自動管理,利用類對象出了作用域會調用析構函數,把對指針的釋放寫在析構函數中,避免出現懸掛指針的情況。
    智能指針(smart pointer)是存儲指向動態分配(堆)對象指針的類,用於生存期控制,能夠確保自動正確的銷燬動態分配的對象,防止內存泄露。它的一種通用實現技術是使用引用計數(reference count)。智能指針類將一個計數器與類指向的對象相關聯,引用計數跟蹤該類有多少個對象共享同一指針。每次創建類的新對象時,初始化指針並將引用計數置爲1;當對象作爲另一對象的副本而創建時,拷貝構造函數拷貝指針並增加與之相應的引用計數;對一個對象進行賦值時,賦值操作符減少左操作數所指對象的引用計數(如果引用計數爲減至0,則刪除對象),並增加右操作數所指對象的引用計數;調用析構函數時,構造函數減少引用計數(如果引用計數減至0,則刪除基礎對象)。
    智能指針就是模擬指針動作的類。所有的智能指針都會重載 -> 和 * 操作符。智能指針還有許多其他功能,比較有用的是自動銷燬。這主要是利用棧對象的有限作用域以及臨時對象(有限作用域實現)析構函數釋放內存。當然,智能指針還不止這些,還包括複製時可以修改源對象等。智能指針根據需求不同,設計也不同(寫時複製,賦值即釋放對象擁有權限、引用計數等,控制權轉移等)。auto_ptr 即是一種常見的智能指針。
  2. 智能指針的實現(用類模板實現)
class Test
{
public:
    Test()
    {
        cout<<"Test()"<<endl;
    }
    ~Test()
    {
        cout<<"~Test()"<<endl;
    }
    void func()
    {
        cout<<"call Test::func()"<<endl;
    }
};
template<typename T>
class CSmartptr
{
public:
    CSmartptr(T *ptr):_ptr(ptr)
    {cout<<"CSmartptr()"<<endl;}
    CSmartptr(const CSmartptr<T> &other)
    {
        _ptr = new T;
        *ptr = *other._ptr;
    }
    ~CSmartptr()
    {
        cout<<"~CSmartptr()"<<endl;
        delete _ptr;
    }
    void relase() const
    {
        ((CSmartptr<T> *)this)->owns = false;
    }
    T& operator*()
    {
        return *_ptr;
    }
    const T& operator*()const {return *_ptr;}
    T *operator->()
    {
        return _ptr;
    }
    const T *operator->()const {return _ptr;}
private:
    T *_ptr;
};
int main()
{
    CSmartptr<int> p1(new int);
    *p1 = 200;
    CSmartptr<Test> p2(new Test);
    p2->func();
    return 0;
}
  1. 模擬實現auto_ptr
template<typename T>
class CSmartptr
{
public:
    CSmartptr(T *ptr):_ptr(ptr),owns(true){cout<<"CSmartptr()"<<endl;}
    CSmartptr(const CSmartptr<T> &other)
    {
        other.relase();
        _ptr = other._ptr;
    }
    ~CSmartptr()
    {
        cout<<"~CSmartptr()"<<endl;
        if( owns == true)
        {
            cout<<"~CSmartptr()"<<endl;
            delete _ptr;
        }

    }
    void relase() const
    {
        ((CSmartptr<T> *)this)->owns = false;
    }
    T& operator*()
    {
        return *_ptr;
    }
    const T& operator*()const {return *_ptr;}
    T *operator->()
    {
        return _ptr;
    }
    const T *operator->()const {return _ptr;}
private:
    T *_ptr;
    bool owns;  //標誌位 ,控制一個資源的訪問權限
};
int main()
{
    CSmartptr<int> p1(new int);
    *p1 = 200;
    CSmartptr<Test> p2(new Test);
    p2->func();
    return 0;
}
  1. 帶有引用計數的智能指針(方便對資源的管理和釋放)
class CHeapTable
{
public:
    static CHeapTable& getInstance()
    {
        return mHeapTable;
    }
    //增加引用計數
    void addRef(void *ptr)
    {
        pthread_mutex_lock(mutex);
        list<Node>::iterator it = find(mList.begin(),
            mList.end(), ptr);  // Node == Node  it->mpaddr
        if(it == mList.end())
        {
            mList.push_front(ptr);
            cout<<"new addr:"<<ptr<<" ref:"<<1<<endl;
        }
        else
        {
            it->mcount++;
            cout<<"add addr:"<<ptr<<" ref:"<<it->mcount<<endl;
        }
        pthread_mutex_unlock(mutex);
    }
    //減少引用計數的
    void delRef(void *ptr)
    {
        list<Node>::iterator it = find(mList.begin(),
            mList.end(), ptr);
        if(it != mList.end())
        {
            it->mcount--;
            cout<<"del addr:"<<ptr<<" ref:"<<it->mcount<<endl;
            if(it->mcount == 0)
            {
                mList.erase(it);
            }
        }
    }
    //獲取引用計數的
    int getRef(void *ptr)
    {
        list<Node>::iterator it = find(mList.begin(),
            mList.end(), ptr);
        if(it != mList.end())
        {
            return it->mcount;
        }
        return 0;
    }
private:
    CHeapTable(){}
    static CHeapTable mHeapTable;

    struct Node
    {
        Node(void *ptr=NULL):mpaddr(ptr),mcount(1){}
        bool operator==(const Node &src)
        {
            return mpaddr == src.mpaddr;
        }
        void *mpaddr; //標識堆內存資源
        int mcount; //標識資源的引用計數
    };

    list<Node> mList;
};
CHeapTable CHeapTable::mHeapTable;
template<typename T>
class CSmartPtr
{
public:
    CSmartPtr(T *ptr = NULL)
        :mptr(ptr)
    {
        if(mptr != NULL)
        {
            addRef();
        }
    }
    ~CSmartPtr()
    {
        delRef();
        if(0 == getRef())
        {
            delete mptr; 
            mptr = NULL;
        }
    }

    CSmartPtr(const CSmartPtr<T> &src)
        :mptr(src.mptr)
    {
        if(mptr != NULL)
        {
            addRef();
        }
    }

    CSmartPtr<T>& operator=(const CSmartPtr<T> &src)
    {
        if(this == &src)
            return *this;

        delRef();
        if(0 == getRef())
        {
            delete mptr;
            mptr = NULL;
        }

        mptr = src.mptr;
        if(mptr != NULL)
        {
            addRef();
        }
    }
    T& operator*(){return *mptr;}
    const T& operator*()const{return *mptr;}
    T* operator->(){return mptr;}
    const T* operator->()const{return mptr;}

    void addRef(){mHeapTable.addRef(mptr);}
    void delRef(){mHeapTable.delRef(mptr);}
    int getRef(){return mHeapTable.getRef(mptr);}
private:
    T *mptr;
     static CHeapTable &mHeapTable;
};
template<typename T>
CHeapTable& CSmartPtr<T>::mHeapTable = CHeapTable::getInstance();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章