以前文章中實現的寫時複製,句柄類中引用計數和T類型指針是分開的,這裏換一種方式來處理,將引用計數和T類型指針視爲一個總體,當作句柄類模板參數。先對上節中的引用計數進行改造:html
這個版本的UseCount和以前的版本差異很大,從析構函數能夠看出(純虛函數),它是基於引用計數來共享的值對象的基類,須要注意的部分:ide
1 class CUseCount 2 { 3 public: 4 CUseCount(); 5 CUseCount(const CUseCount&); 6 CUseCount& operator=(const CUseCount&); 7 virtual ~CUseCount() = 0; 8 9 void markUnshareable(); 10 bool isShareable() const; 11 bool isShared() const; 12 13 void addReference(); 14 void removeReference(); 15 16 private: 17 int refCount; //注意這裏非int指針 18 bool shareable; //是不是共享狀態 19 }; 20 21 CUseCount::CUseCount():refCount(0), shareable(true) 22 {} 23 24 CUseCount::CUseCount(const CUseCount& u):refCount(0), shareable(true) 25 {} 26 27 CUseCount& CUseCount::operator=(const CUseCount& u) 28 { 29 return *this; 30 } 31 32 CUseCount::~CUseCount() 33 {} 34 35 void CUseCount::markUnshareable() 36 { 37 shareable = false; 38 } 39 40 bool CUseCount::isShareable() const 41 { 42 return shareable; 43 } 44 45 bool CUseCount::isShared() const 46 { 47 return refCount > 1; 48 } 49 50 void CUseCount::addReference() 51 { 52 ++refCount; 53 } 54 55 void CUseCount::removeReference() 56 { 57 if(--refCount == 0) 58 delete this; 59 }
接下來看看這一版本中的Handle類:函數
1 template<class T> class Handle 2 { 3 public: 4 Handle(T *p = 0); 5 Handle(const Handle& h); 6 Handle& operator=(const Handle&); 7 ~Handle(); 8 //other member functions
9 private: 10 T* ptr; 11 void init(); 12 }; 13
14 template<class T>
15 inline Handle<T>::init() 16 { 17 if(ptr == 0) 18 return; 19 if(ptr->isShareable() == false) //非共享狀態,進行復制
20 ptr = new T(*ptr); 21
22 ptr->addReference(); //引用計數增長
23 } 24
25 template<class T>
26 inline Handle<T>::Handle(T* p):ptr(p) //u 默認構造函數
27 { 28 init(); 29 } 30
31 template<class T>
32 inline Handle<T>::Handle(const Handle& rhs):ptr(rhs.ptr) 33 { 34 init(); 35 } 36
37 template<class T>
38 inline Handle<T>& Handle<T>::operator=(const Handle& rhs) 39 { 40 if(ptr != rhs.ptr) 41 { 42 if(ptr != NULL) 43 { 44 ptr->removeReference(); 45 } 46 ptr = rhs.ptr; 47 init(); 48 } 49 return *this; 50 } 51
52 template<class T>
53 inline Handle<T>::~Handle() 54 { 55 if(ptr) 56 ptr->removeReference(); 57 }
修改後的Handle類比以前的要複雜一些:this
使用本節中實現的UseCount和Handle來處理寫時複製,一個String類的例子以下:spa
1 class String 2 { 3 public: 4 String(const char *value = ""); 5 const char& operator[](int index) const; 6 char& operator[](int index); 7 private: 8 struct StringValue: public CUseCount //繼承自引用計數
9 { 10 char *data; 11 StringValue(const char *initValue); 12 StringValue(const StringValue& rhs); 13 void init(const char *initValue); 14 ~StringValue(); 15 }; 16 Handle<StringValue> value; 17 }; 18
19 void String::StringValue::init(const char *initValue) 20 { 21 data = new char[strlen(initValue) + 1]; 22 strcpy(data, initValue); 23 } 24
25 String::StringValue::StringValue(const char *initValue) 26 { 27 init(initValue); 28 } 29
30 String::StringValue::StringValue(const StringValue& rhs) 31 { 32 init(rhs.data); 33 } 34
35 String::StringValue::~StringValue() 36 { 37 delete [] data; 38 } 39
40 String::String(const char *initValue): value(new StringValue(initValue)) 41 {} 42
43 const char& String::operator[](int index) const //const函數不進行復制
44 { 45 return value->data[index]; 46 } 47
48 char& String::operator[](int index) 49 { 50 if (value->isShared()) 51 { 52 value = new StringValue(value->data); //先調用基類UseCount拷貝構造函數
53 } 54 value->markUnshareable(); 55 return value->data[index]; 56 }
代碼中能夠看出,String內部實現由StringValue完成,Handle句柄託管StringValue類型指針,StringValue繼承自UseCount類,其子對象部分負責char*的管理,,父對象即UseCount完成對象的計數、共享以及銷燬工做,以圖來表示例子中各個類的關係以下:3d
代碼中還有一些須要的地方:指針
1 char& String::operator[](int index) 2 { 3 if (value->isShareable()) 4 { 5 value = new StringValue(value->data); //先調用基類UseCount拷貝構造函數
6 } 7 value->markUnshareable(); 8 return value->data[index]; 9 } 10
11 int main() 12 { 13 String s("Grubby"); 14 char c = s[3]; 15
16 return 0; 17 }
main函數中line14,調用了operator[] 操做符,按上述代碼實現,line3先判斷if(value->isShareable()),而s對象剛剛定義沒有使用,UseCount構造函數中設置isShare=true,因此if判斷返回true,運行語句value = new StringValue(value->data),從新構造value是沒有必要的。而判斷若是是if(isShared()),此時refCount==1,因此沒有共享if返回false,不會從新構造value。code
這一節中的代碼,借鑑了《more effective C++》中的引用計數章節,加上了一些本身的我的理解,文章中難免有誤,還請你們指正。htm
未完待續……對象