智能指針簡單實現

   很多人都誤以爲智能指針是一個指針,其實不然,智能指針不是指針,智能指針是一個模板,由智能指針實例化出來的的對象具有和常規指針相似的行爲,但是他能夠自動的釋放所指向的對象,所以我們稱之爲智能指針。如果我們用普通指針來創建一個指向某個對象的指針,那麼我們最後必須要手動釋放這塊空間,而智能指針它是一個類,它釋放空間是通過析構函數完成的,正是由於有了這一層封裝機制,所以智能指針才能夠管理一個對象的生命週期。(定義一個類來封裝資源的分配和釋放,在構造函數完成資源的分配和初始化,在析構函數完成資源的清理,可以保證資源的正確初始化和釋放。這樣的方法稱爲RAII)


  起初在C++標準庫裏面是沒有智能指針的,直到C++11中才加入了shared_ptr和unique_ptr,weak_ptr。最早的智能指針在Boost庫裏面,Boost是爲C++標準庫提供擴展的一些C++程序的總稱,由Boost社區組織開發維護。


1、auto_ptr

   auto_ptr在STL中早就存在了,auto_ptr是通過權限轉移的方式來防止值拷貝所帶來問題,所謂權限轉移就是說開闢的動態內存任何時刻只能由一個指針指向。



下面通過實現自己的AutoPtr來剖析一下auto_ptr。現在已經不用aotu_ptr了,常用的是scoped_ptr和shared_ptr.


<span style="font-size:14px;">template<typename T>
class AutoPtr                       //AutoPtr是一個類模板,不是指針類型
{
public:
       AutoPtr(T* ptr=0);
       AutoPtr(AutoPtr<T>& ap);
       AutoPtr<T>& operator=(AutoPtr<T>& ap);
       T* Get();
       T* Release();
       void Reset(T* ptr=0);
       T& operator*();
       T* operator->();
       ~AutoPtr();
private:
       T* _ptr;
};
template<typename T>
T* AutoPtr<T>::Get()
{
       return _ptr;
}
template<typename T>
T* AutoPtr<T>::Release()
{
       T* tmp = _ptr;
       _ptr = NULL;
       return tmp;
}
template<typename T>
void AutoPtr<T>::Reset(T* ptr = 0)
{
       delete _ptr;
       _ptr = ptr;
       ptr = NULL;
}
template<typename T>
AutoPtr<T>::AutoPtr(T* ptr=0)
:_ptr(ptr){}
template<typename T>
AutoPtr<T>::AutoPtr(AutoPtr<T>& ap)        //auto_ptr採用權限轉移的方式,確保始終只有一個指針指向這塊空間
{
       _ptr = ap._ptr;
       ap._ptr = NULL;          //權限轉移
}
template<typename T>
AutoPtr<T>& AutoPtr<T>::operator=(AutoPtr<T>& ap)
{
       delete _ptr;
       _ptr = ap._ptr;
       ap._ptr = NULL;           //權限轉移
       return *this;
}
template<typename T>
T& AutoPtr<T>::operator*()
{
       return *_ptr;
}
template<typename T>
T* AutoPtr<T>::operator->()          //有特殊處理
{
       return _ptr;
}
template<typename T>
AutoPtr<T>::~AutoPtr()
{
       if (_ptr != NULL)
       {
              delete _ptr;
              _ptr = NULL;
       }
}</span><span style="font-size: 19px;">
</span>



下面我們先來介紹boost庫中的幾種常用的智能指針,由於boost庫不是C++標準庫,所以我們在使用boost中的智能指針之前先要下載一個boost庫,並把它包含到C++標準庫中。


1、scoped_ptr

  由於auto_ptr的行爲與真正的指針有很大區別,尤其是權限轉移這種方法。爲了防止值拷貝帶來的問題,所以scoped_ptr從根本上就不允許拷貝和賦值(防賦值、防拷貝)。


template<typename T>
class ScopedPtr   //防拷貝,防賦值,使得scopedptr看起來更像一個指針類型,但實際上scopedptr是一個類模板
{
public:
       explicit ScopedPtr(T* ptr);
       T& operator*();
       T* operator->();
       ~ScopedPtr();
       T* Get() const;
       void Reset(T *p=0);
       void Swap(ScopedPtr<T>& sp);
protected:
       ScopedPtr(const ScopedPtr<T>& sp);                         //將拷貝和賦值運算符聲明爲保護,防賦值、防拷貝
       ScopedPtr<T>& operator=(const ScopedPtr<T>& ap);
private:
       T* _ptr;
};
template<typename T>
T* ScopedPtr<T>::Get() const
{
       return _ptr;
}
template<typename T>
void ScopedPtr<T>::Reset(T *p = 0)
{
       delete _ptr;
       _ptr = p;
       p = NULL;
}
template<typename T>
void ScopedPtr<T>::Swap(ScopedPtr<T>& sp)
{
       swap(_ptr,sp._ptr);
}
template<typename T>
ScopedPtr<T>::ScopedPtr(T* ptr)
:_ptr(ptr)
{}
template<typename T>
T& ScopedPtr<T>::operator*()
{
       return *_ptr;
}
template<typename T>
T* ScopedPtr<T>::operator->()           //有特殊處理
{
       return _ptr;
}
template<typename T>
ScopedPtr<T>::~ScopedPtr()
{
       if (NULL!= _ptr)
       {
              delete _ptr;
              _ptr =NULL;
       }
}



2、scoped_array

scoped_array是用來管理數組的。


<span style="font-size:14px;">template<typename T>
class ScopedArray
{
public:
       ScopedArray(T* ptr);
       ~ScopedArray();
       T& operator[](size_t index);
       void Reset(T* ptr=0);
       T* Get() const;
protected:
       ScopedArray(const ScopedArray<T>&);
       ScopedArray<T>& operator=(const ScopedArray<T>&);
private:
       T* _ptr;
};
template<typename T>
void ScopedArray<T>::Reset(T* ptr = 0)
{
       if (_ptr != ptr||_ptr==NULL)
       {
              delete[] _ptr;
              _ptr = ptr;
              ptr = NULL;
       }
}
template<typename T>
T* ScopedArray<T>::Get() const
{
       return _ptr;
}
template<typename T>
ScopedArray<T>::ScopedArray(T* ptr)
:_ptr(ptr)
{}
template<typename T>
ScopedArray<T>::~ScopedArray()
{
       if (NULL != _ptr)
       {
              delete[] _ptr;
              _ptr = NULL;
       }
}
template<typename T>
T& ScopedArray<T>::operator[](size_t index)
{
       return _ptr[index];
}</span><span style="font-size: 24px;">
</span>



3、shared_ptr

  shared_ptr允許拷貝和賦值,其底層實現是以"引用計數"爲基礎的,通過引用計數來控制空間的釋放,當一塊空間創建時引用計數爲1,當有新的指針指向這塊空間時,引用計數加1,反之減1,直到引用計數減爲0時才真的釋放這塊空間。所以說shared_ptr更像一個指針。


template<typename T>
class SharedPtr            //採用引用計數,實現一個可以有多個指針指向同一塊內存的類模板,SharedPtr是類模板,不是智能指針類型
{
public:
       SharedPtr(T* ptr);
       SharedPtr(const SharedPtr<T>& sp);
       SharedPtr<T>& operator=(SharedPtr<T> sp);
       T& operator*();
       T* operator->();
       ~SharedPtr();
       int Count()
       {
              return *_pCount;
       }
private:
       void Release()
       {
              if (--(*_pCount) == 0)
              {
                     delete _ptr;
                     delete _pCount;
                     _ptr = NULL;
                     _pCount = NULL;
              }
       }
private:
       T* _ptr;
       int* _pCount;             //指向引用計數的空間
};
template<typename T>
SharedPtr<T>::SharedPtr(T* ptr)
:_ptr(ptr)
, _pCount(new int(1)){}
template<typename T>
SharedPtr<T>::SharedPtr(const SharedPtr<T>& sp)
{
       _ptr = sp._ptr;
       _pCount= sp._pCount;
       ++(*_pCount);
}
template<typename T>
SharedPtr<T>& SharedPtr<T>::operator=(SharedPtr<T> sp)
{
       std::swap(sp._ptr,_ptr);
       std::swap(sp._pCount,_pCount);
       return *this;
}
template<typename T>
T& SharedPtr<T>::operator*()
{
       return *_ptr;
}
template<typename T>
T* SharedPtr<T>::operator->()
{
       return _ptr;
}
template<typename T>
SharedPtr<T>::~SharedPtr()
{
       Release();
}



4、shared_array

shared_array也是管理數組的。


<span style="font-size:14px;">template<typename T>
class SharedArray
{
public:
       SharedArray(T* ptr);
       ~SharedArray();
       SharedArray(const SharedArray<T>& sp);
       SharedArray<T>& operator=(SharedArray<T> sp);
       T& operator[](size_t index);
private:
       T* _ptr;
       int* _pCount;
};
template<typename T>
SharedArray<T>::SharedArray(T* ptr)
:_ptr(ptr)
, _pCount(new int(1))
{}
template<typename T>
SharedArray<T>::~SharedArray()
{
       if (--(*_pCount) == 0)
       {
              delete[] _ptr;
              _ptr = NULL;
              delete _pCount;
              _pCount = NULL;
       }
}
template<typename T>
SharedArray<T>::SharedArray(const SharedArray<T>& sp)
{
       _ptr = sp._ptr;
       _pCount = sp._pCount;
       ++*pCount;
}
template<typename T>
SharedArray<T>& SharedArray<T>::operator=(SharedArray<T> sp)
{
       swap(_ptr,sp._ptr);
       swap(_pCount,sp._pCount);
       return *this;
}
template<typename T>
T& SharedArray<T>::operator[](size_t index)
{
       return _ptr[index];
}</span><span style="font-size: 24px;">
</span>



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