智能指針(模擬實現AutoPtr、ScopedPtr、SharedPtr)

        模擬實現AutoPtr、ScopedPtr、SharedPtr


        智能指針實際上就是能夠智能化的管理動態開闢空間的內存釋放問題,C++中引入智能指針,很大一方面是當我們在動態開闢空間時,由於一些疏忽,或者說是對於一些代碼,執行的順序不是我們預期能夠想到的,導致一些內存泄露的問題,使得程序健壯性不夠,可維護性降低。


       智能指針的基本特點:

              1)智能指針管理的是一塊內存的釋放。

              2)智能指針是一個類,有類似指針的功能。


下面主要是AutoPtr的理解:

        當我們瞭解上面的知識後,模擬實現智能指針AutoPtr,可能會寫出下列的代碼:

//智能指針AutoPtr

template <class T>
class AutoPtr
{
public:
    AutoPtr(T * ptr)
        :_ptr(ptr)
    { }
    
    ~AutoPtr()
    {
        cout << "delete" << _ptr << endl;
        if (_ptr)
        {
            delete _ptr;
            _ptr = NULL;
         }
    }
    
private:
    T * _ptr;
};

       上面的代碼是存在一些問題的,class  AutoPtr只是實現了構造函數和析構函數,對於拷貝構造函數和賦值運算符重載是系統默認的,系統默認情況下是值拷貝,存在一塊空間被釋放兩次及以上的情況,導致程序運行錯誤。對於以前string類的實現採用的是“深拷貝”,但是在這種情況下,不能採用深拷貝來解決,需要使得兩個指針必須指向同一塊空間。AutoPtr的原理就是將第一個指向這塊空間的指針直接置爲空,然後進行析構。這樣就不會存在上述問題。


wKioL1bzrUeyVwgGAAATF6HUaNM982.png

  AutoPtr(AutoPtr<T> & ap)       //拷貝構造
     :_ptr(ap._ptr)
 {
     ap._ptr = NULL;
     cout << "kaobei" << endl;
 }
 
 AutoPtr<T> & operator=(AutoPtr<T> & ap)
 {
     if (this != &ap)
     {
         delete _ptr;
         _ptr = ap._ptr;
         ap._ptr = NULL;
     }
     return *this;
 }
 //下面是實現*、->等功能
 T& operator*()
 {
     return *_ptr;
 }
 T* operator->()
 {
     return _ptr;
 }
 T* GetPtr()
 {
     return _ptr;
 }

        這裏要說明的是,AutoPtr這個指針儘量不要使用,因爲可能在寫代碼時不注意就會出錯。


下面主要是ScopedPtr的理解:


       因爲智能指針容易出現拷貝時釋放兩次的情況,所以ScopedPtr主要是進行防止拷貝防止拷貝的兩條必須要滿足的條件是:

          1)設置保護限定符,

          2)對拷貝構造函數和賦值運算符重載進行之聲明不定義。

          如若只有2),沒有設置保護限定符,若在類外進行定義後,則會出現問題,所以說這兩個條件是必不可少的。這樣就能夠避免上面所出現的問題,但是這樣就造成了它在功能上的缺陷。


//ScopedPtr    實現簡單的智能指針
//進行防拷貝
template <class T>
class ScopedPtr
{
public:
     ScopedPtr(T * ptr)
         :_ptr(ptr)
     { }
     
     ~ScopedPtr()
     {
         cout << "delete" << endl;
         if (_ptr)
         {
             delete _ptr;
             _ptr = NULL;
         }
     }
     
     T & operator*()
     {
         return *_ptr;
      }
      
     T* operator->()
    {
         return _ptr;
     }
     
     T* GetPtr()
    {
        return _ptr;
    }
    
protected:     //防止拷貝
    ScopedPtr(ScopedPtr<T> & ap);
    ScopedPtr<T> & operator=(ScopedPtr<T> & ap);
 
private:
    T * _ptr;
};

        ScopedPtr指針是比較容易實現的,如果面試時出現需要實現一個智能指針的題目,可以考慮實現ScopedPtr,畢竟可以在短時間內實現,也同樣較實現AutoPtr好一些。


下面主要是SharedPtr的理解:


       SharedPtr指針主要的原理是利用引用計數的淺拷貝來實現,通過多開闢4個字節的方式,存儲引用計數,當有指針指向這塊空間時,引用計數+1。如若析構時,先將這塊空間的引用計數降爲1,然後在進行析構,避免了析構多次的問題。


template <class T>
//智能指針sharedptr
class SharedPtr
{
public:
    SharedPtr(T * ptr)
       :_ptr(ptr)
       , _pcount(new long(1))
    { }
    
    ~SharedPtr()
    {
        cout << "delete" << endl;
        if (--(*_pcount) == 0)
        {
            delete _ptr;
            delete _pcount;
        }
    }
    
    SharedPtr(SharedPtr<T> & ap)
       :_ptr(ap._ptr)
       , _pcount(ap._pcount)
    {
        ++(*_pcount);
    }
    
    SharedPtr<T> & operator=(SharedPtr<T> & ap)
   {
       if (this != &ap)
       {
           if (--(*_pcount) == 0)
           {
               delete _ptr;
               delete _pcount;
           }
           _ptr = ap._ptr;
           _pcount = ap._pcount;
           ++(*_pcount);
       }
       return *this;
    }
    
private:
    T * _ptr;
    long *_pcount;    //實現引用計數
};


本文出自 “無心的執着” 博客,謝絕轉載!

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