auto_ptr與scoped_ptr的實現見本人的上篇博客。安全
3、shared_ptride
shared_ptr的實現原理是經過引用計數來實現,只有當引用計數爲1時才釋放空間,不然只需將引用計數減1.拷貝和賦值將引用計數加1,具體代碼以下:函數
template <typename T> class SharedPtr { public: SharedPtr(); SharedPtr(T* ptr); SharedPtr(const SharedPtr<T>& ap); ~SharedPtr(); //SharedPtr<T>& operator=(const SharedPtr<T>& ptr);//傳統寫法 SharedPtr<T>& operator=(SharedPtr<T> ap);//現代寫法 T& operator*()const; T* operator->()const; long GetCount()const; T* GetPtr()const; protected: void _Realease(); protected: T* _ptr; long* _pCount; }; template <typename T> SharedPtr<T>::SharedPtr() :_ptr(NULL), _pCount(new long(1)) {} template <typename T> SharedPtr<T>::SharedPtr(T* ptr) : _ptr(ptr), _pCount(new long(1)) {} template <typename T> SharedPtr<T>::SharedPtr(const SharedPtr<T>& ap) : _ptr(ap._ptr), _pCount(ap._pCount) { ++(*this->_pCount); } template <typename T> SharedPtr<T>::~SharedPtr() { this->_Realease(); } //template <typename T>//傳統寫法 //SharedPtr<T>& SharedPtr<T>::operator=(const SharedPtr<T>& ap) //{ // if (this->_ptr != ap._ptr) // { // this->_Realease(); // this->_ptr = ap._ptr; // this->_pCount = ap._pCount; // ++(*this->_pCount); // } // return *this; //} template <typename T>//現代寫法 SharedPtr<T>& SharedPtr<T>::operator=(SharedPtr<T> ap) { swap(this->_ptr, ap._ptr); swap(this->_pCount, ap._pCount); return *this; } template <typename T> T& SharedPtr<T>::operator*()const { return *(this->_ptr); } template <typename T> T* SharedPtr<T>::operator->()const { return this->_ptr; } template <typename T> long SharedPtr<T>::GetCount()const { return *(this->_pCount); } template <typename T> T* SharedPtr<T>::GetPtr()const { return this->_ptr; } template <typename T> void SharedPtr<T>::_Realease() { if (--(*this->_pCount) == 0) { delete this->_ptr; delete this->_pCount; } }
然而上面用引用計數實現的簡化版看起來不錯,但卻存在如下問題:
this
一、引用計數更新存在着線程安全spa
二、循環引用線程
三、定置刪除器,好比要關閉一個文件,用malloc開闢出來的空間,上述代碼均會出現問題指針
問題1的解決須要對改變引用計數時加鎖。咱們暫時不討論,一下咱們主要看第二個和第三個問題。對象
循環引用:
博客
好比有如下結構體和主函數:it
struct ListNode { shared_ptr<ListNode> _prev; //shared_ptr爲庫文件中實現的,只需包memory便可使用 shared_ptr<ListNode> _next; ~ListNode() { cout << "~ListNode()" << endl; } }; int main() { shared_ptr<ListNode> prev; //語句1 shared_ptr<ListNode> next; //語句2 prev->_next = next; //語句3 next->_prev = prev; //語句4 }
經語句一、2以後prev的引用計數爲1,經三、4後爲2,可是最後兩個對象均不能釋放,由於prev的要釋放的前提是next釋放,而next的釋放又依賴於prev的釋放。最後就造成了循環引用,誰都是放不了。解決方案以下:
struct ListNode { weak_ptr<ListNode> _prev; weak_ptr<ListNode> _next; ~ListNode() { cout << "~ListNode()" << endl; } };
由於weak_ptr(弱引用智能指針)會對引用計數會作特殊處理(上述狀況不加1)。
定置刪除器和空間分配器(ps:空間分配器的定置特殊場景下才會這樣使用)
eg:若是指針是一個指向文件類型的,在析構函數中只需關閉文件便可,而不是釋放空間;若是空間是經過,malloc出來的,那麼在析構函數中要調用free函數,而不是delete操做符。上述問題經過仿函數就能夠解決。具體代碼以下:
template <typename T,class Deleter = Del<T>> class SharedPtr { public: SharedPtr(T* ptr); SharedPtr(T* ptr, Deleter del); SharedPtr(const SharedPtr<T, Deleter>& ap); ~SharedPtr(); //SharedPtr<T, Deleter>& operator=(const SharedPtr<T, Deleter>& ptr);//傳統寫法 //現代寫法 SharedPtr<T, Deleter>& operator=(SharedPtr<T, Deleter> ap); T& operator*()const; T* operator->()const; long GetCount()const; T* GetPtr()const; protected: void _Realease(); protected: T* _ptr; long* _pCount; Deleter _del; }; template <typename T, class Deleter = Del<T>> SharedPtr<T, Deleter>::SharedPtr(T* ptr) :_ptr(ptr), _pCount(new long(1)) {} template <typename T, class Deleter = Del<T>> SharedPtr<T, Deleter>::SharedPtr(T* ptr, Deleter del) : _ptr(ptr), _pCount(new long(1)), _del(del) {} template <typename T, class Deleter = Del<T>> SharedPtr<T, Deleter>::SharedPtr(const SharedPtr<T, Deleter>& ap) : _ptr(ap._ptr), _pCount(ap._pCount), _del(ap._del) { ++(*this->_pCount); } template <typename T, class Deleter = Del<T>> SharedPtr<T, Deleter>::~SharedPtr() { this->_Realease(); } //template <typename T, class Deleter = Del<T>>//傳統寫法 //SharedPtr<T, Deleter>& SharedPtr<T, Deleter>::operator=(SharedPtr<T, Deleter> ap) //{ // if (this->_ptr != ap._ptr) // { // this->_Realease(); // this->_ptr = ap._ptr; // this->_pCount = ap._pCount; // ++(*this->_pCount); // } // return *this; //} template <typename T, class Deleter = Del<T>>//現代寫法 SharedPtr<T, Deleter>& SharedPtr<T, Deleter>::operator=(SharedPtr<T, Deleter> ap) { swap(this->_ptr, ap._ptr); swap(this->_pCount, ap._pCount); swap(this->_del, ap._del); return *this; } template <typename T, class Deleter = Del<T>> T& SharedPtr<T, Deleter>::operator*()const { return *(this->_ptr); } template <typename T, class Deleter = Del<T>> T* SharedPtr<T, Deleter>::operator->()const { return this->_ptr; } template <typename T, class Deleter = Del<T>> long SharedPtr<T, Deleter>::GetCount()const { return *(this->_pCount); } template <typename T, class Deleter = Del<T>> T* SharedPtr<T, Deleter>::GetPtr()const { return this->_ptr; } template <typename T, class Deleter = Del<T>> void SharedPtr<T, Deleter>::_Realease() { if (--(*this->_pCount) == 0) { _del(_ptr); delete this->_pCount; } }