std::shared_ptr
是通過指針保持對象共享所有權的智能指針。多個 shared_ptr
對象可占有同一對象大概實現了一下,主要實現原理為,共享指針內部持有堆資源的指針以及引用計數的指針,通過對這兩個指針的維護,達到多個共享對象對同一資源的控制
實現主要分為三個文件。share_ptr.h,smart_ptr_define.h, main.cpp (編譯平台:Linux centos 7.0 編譯器:gcc 4.8.5 )
1 //smart_ptr_define.h 2 #ifndef __SMART_PTR_DEFINE_H__ 3 #define __SMART_PTR_DEFINE_H__ 4 5 #include <assert.h> 6 7 #define PTR_ASSERT(x) assert(x) 8 9 #define _SMART_PTR_BEGIN namespace smartptr { 10 #define _SMART_PTR_END } 11 #define _SMART_PTR ::smartptr:: 12 13 #endif
主要實現文件share_ptr.h
1 #ifndef __SHARE_PTR_H__ 2 #define __SHARE_PTR_H__ 3 4 #include <iostream> 5 #include "smart_ptr_define.h" 6 7 _SMART_PTR_BEGIN 8 9 template <class T> 10 struct default_deleter 11 { 12 void operator()(T* ptr) 13 { 14 if (ptr != NULL) 15 { 16 delete ptr; 17 ptr = NULL; 18 } 19 } 20 }; 21 22 template <class T, class deleter = default_deleter<T> > 23 class shared_ptr 24 { 25 public: 26 typedef shared_ptr<T, deleter> SHARE_PTR; 27 28 shared_ptr() 29 { 30 m_ptr = NULL; 31 m_iRefCount = NULL; 32 } 33 34 explicit shared_ptr(T* ptr) 35 { 36 if (ptr != NULL) 37 { 38 m_ptr = ptr; 39 RefCountInit(); 40 } 41 } 42 43 shared_ptr(deleter d, T* ptr) 44 { 45 if (ptr != NULL) 46 { 47 m_ptr = ptr; 48 m_deleter = d; 49 RefCountInit(); 50 } 51 } 52 53 //拷貝構造 54 shared_ptr(const SHARE_PTR& sh_ptr) 55 { 56 if (sh_ptr.m_ptr != NULL) 57 { 58 m_ptr = sh_ptr.m_ptr; 59 m_deleter = sh_ptr.m_deleter; 60 m_iRefCount = sh_ptr.m_iRefCount; 61 62 RefCountIncrease(); 63 } 64 } 65 66 //賦值運算符 67 SHARE_PTR& operator = (const SHARE_PTR& sh_ptr) 68 { 69 if (this != &sh_ptr) 70 { 71 RefCountDecrease(); 72 73 if (sh_ptr.m_ptr != NULL) 74 { 75 m_ptr = sh_ptr.m_ptr; 76 m_deleter = sh_ptr.m_deleter; 77 m_iRefCount = sh_ptr.m_iRefCount; 78 79 RefCountIncrease(); 80 } 81 } 82 83 return (*this); 84 } 85 86 ~shared_ptr() 87 { 88 RefCountDecrease(); 89 } 90 91 public: 92 //提領操作 93 T& operator*() 94 { 95 PTR_ASSERT(m_ptr != NULL); 96 return *(m_ptr); 97 } 98 99 //原始指針操作 100 T* operator->() 101 { 102 PTR_ASSERT(m_ptr != NULL); 103 return m_ptr; 104 } 105 106 operator bool() const 107 { 108 return m_ptr != NULL; 109 } 110 111 //取得原始指針 112 T* getPointer() 113 { 114 PTR_ASSERT(m_ptr != NULL); 115 return m_ptr; 116 } 117 118 //獲得引用計數 119 int getRefCount() 120 { 121 PTR_ASSERT(m_iRefCount != NULL); 122 return *m_iRefCount; 123 } 124 125 126 private: 127 void RefCountInit() 128 { 129 m_iRefCount = new int(1); 130 } 131 132 void RefCountIncrease() 133 { 134 if (m_iRefCount != NULL) 135 { 136 ++(*m_iRefCount); 137 } 138 } 139 140 void RefCountDecrease() 141 { 142 if (m_iRefCount != NULL && --(*m_iRefCount) == 0) 143 { 144 m_deleter(m_ptr); 145 delete m_iRefCount; 146 m_ptr = NULL; 147 m_iRefCount = NULL; 148 } 149 } 150 151 private: 152 int* m_iRefCount; //引用計數 153 154 T* m_ptr; //對象指針 155 156 deleter m_deleter; //刪除器 157 }; 158 159 _SMART_PTR_END 160 #endif // !__SHARE_PTR_H__
main函數測試
1 #include "share_ptr.h" 2 #include <memory> 3 4 class Test 5 { 6 public: 7 Test() 8 { 9 std::cout << "construct.." << std::endl; 10 } 11 12 void method() 13 { 14 std::cout << "welcome Test.." << std::endl; 15 } 16 17 ~Test() 18 { 19 std::cout << "destruct.." << std::endl; 20 } 21 }; 22 23 int main() 24 { 25 Test* t1 = new Test(); 26 27 _SMART_PTR shared_ptr<Test> shptr(t1); 28 29 _SMART_PTR shared_ptr<Test> shptr1(shptr); 30 31 _SMART_PTR shared_ptr<Test> shptr2 = shptr1; 32 33 std::cout << "RefCount: " << shptr2.getRefCount() << std::endl; 34 35 shptr2->method(); 36 37 (*shptr2).method(); 38 39 if (shptr2) 40 { 41 std::cout << "ptr is exit " << std::endl; 42 } 43 44 45 46 return 0; 47 }
測試最后打印:
1 [yejy@yejy cmake-00]$ ./smartptr 2 construct.. 3 RefCount: 3 4 welcome Test.. 5 welcome Test.. 6 ptr is exit 7 destruct.. 8 [yejy@yejy cmake-00]$
shared_ptr主要需實現的功能點如下(以下總結引用自網絡,非原創):
-
沒有參數構造的時候,初始化為空,即對象和引用計數的兩個指針都為0
-
使用指針為參數構造時,擁有此指針,在沒有智能指針指向它時進行析構
-
智能指針復制時,兩個智能指針共同擁有內部指針,引用計數同時+1
-
智能指針可以使用智能指針或普通指針重新賦值。重載=操作符,對於智能指針賦值,需要考慮是否自賦值,以避免將自身析構了后再重新賦值,而普通指針賦值給智能指針,則不需要考慮自賦值,因為兩者本身是兩個類型
-
獲得底層指針的訪問,定義
getPtrPointer()
和getPtrCounter()
來分別返回底層指針和引用計數,定義operator bool()
來處理智能指針隱式轉換為bool
的情況 -
重載
->
和×
操作符 ,來實現與普通指針相同的指針訪問 -
需要支持隱式指針類型轉換,
static_cast
不支持而dynamic_cast
支持的轉換則使用Cast<T2>()
成員函數來解決。考慮定義友元類,以防止指向派生類的智能指針有權限訪問基類的內部對象;當轉型不成功時,返回為空 (未實現) -
如果一個裸指針直接用來創建兩個智能指針的話,期望的情況是當兩個智能指針析構掉的時候,該指針會被delete兩次從而崩潰(這是
shared_ptr
的特點) -
不處理循環引用(也是
shared_ptr
的特點),可以通過與weak_ptr
協作來打破循環 -
實現
deleter
機制