三、引用计数基类和智能指针实现的String类
//RCObject.h #ifndef RCOBJECT_H #define RCOBJECT //引用计数基类 class RCObject{ public: void addReference();//增加引用计数 void removeReference();//减少引用计数,如果变为0,销毁对象 void markUnshareable();//将追踪其值是否可共享的成员设为false bool isShareable() const;//判断其值是否可共享 bool isShared() const;//判断其值是否正在被共享 int getRefCount();//返回引用计数 protected: RCObject();//构造函数 RCObject(const RCObject& rhs);//拷贝构造函数 RCObject& operator=(const RCObject& rhs);//拷贝赋值运算符 virtual ~RCObject() = 0;//析构函数 private: int refCount;//保存引用计数 bool shareable;//保存其值是否可共享的状态 }; //构造函数,这里refCount设为0,让对象创建者自行或将refCoun设为1 RCObject::RCObject(void) :refCount(0), shareable(true){} //拷贝构造函数,总是将refCount设为0,因为正在产生一个新对象,只被创建者引用 RCObject::RCObject(const RCObject&) : refCount(0), shareable(true){} //拷贝赋值运算符,这里只返回*this,因为左右两方RCObject对象的外围对象个数不受影响 RCObject& RCObject::operator=(const RCObject& rhs){ return *this; } //析构函数 RCObject::~RCObject(){} //增加引用计数 void RCObject::addReference(){ ++refCount; } //减少引用计数,如果变为0,销毁对象 void RCObject::removeReference(){ if (--refCount == 0) delete this; } //将追踪其值是否可共享的成员设为false void RCObject::markUnshareable(){ shareable = false; } //判断其值是否可共享 bool RCObject::isShareable() const{ return shareable; } //判断其值是否正在被共享 bool RCObject::isShared() const{ return refCount>1; } //返回引用计数 int RCObject::getRefCount(){ return refCount; } #endif //RCPtr.h #ifndef RCPTR_H #define RCPTR_H //智能指针模板类,用来自动执行引用计数类成员的操控动作 template<typename T> class RCPtr{ public: RCPtr(T* realPtr = 0);//构造函数 RCPtr(const RCPtr& rhs);//拷贝构造函数 ~RCPtr();//析构函数 RCPtr& operator=(const RCPtr& rhs);//拷贝赋值运算符 T* operator->() const;//重载->运算符 T& operator*() const;//重载*运算符 private: T* pointee; void init();//共同的初始化操作 }; //共同的初始化操作 template<typename T> void RCPtr<T>::init(){ if (pointee == 0) return; if (pointee->isShareable() == false) { pointee = new T(*pointee); } pointee->addReference(); } //构造函数 template<typename T> RCPtr<T>::RCPtr(T* realPtr) :pointee(realPtr){ init(); } //拷贝构造函数 template<typename T> RCPtr<T>::RCPtr(const RCPtr& rhs) : pointee(rhs.pointee){ init(); } //析构函数 template<typename T> RCPtr<T>::~RCPtr(){ if (pointee) pointee->removeReference(); } //拷贝赋值运算符 template<typename T> RCPtr<T>& RCPtr<T>::operator=(const RCPtr& rhs){ if (pointee != rhs.pointee) { if (pointee) pointee->removeReference(); pointee = rhs.pointee; init(); } return *this; } //重载->运算符 template<typename T> T* RCPtr<T>::operator->() const { return pointee; } //重载*运算符 template<typename T> T& RCPtr<T>::operator*() const { return *pointee; } #endif //String.h #ifndef STRING_H #define STRING_H #define _CRT_SECURE_NO_WARNINGS #include"RCObject.h" #include"RCPtr.h" #include<iostream> class String { public: String(const char *value = "");//构造函数 const char& operator[](int index) const;//重载[]运算符,针对const Strings char& operator[](int index);//重载[]运算符,针对non-const Strings int getRefCount();//返回引用计数 friend std::istream& operator>>(std::istream& is, const String& str);//重载>>运算符 friend std::ostream& operator<<(std::ostream& os, const String& str);//重载<<运算符 private: struct StringValue : public RCObject {//继承自引用计数基类 char *data; StringValue(const char *initValue);//构造函数 StringValue(const StringValue& rhs);//拷贝赋值运算符 void init(const char *initValue); ~StringValue();//析构函数 }; RCPtr<StringValue> value;//智能指针对象 }; //String::StringValue实现代码 void String::StringValue::init(const char *initValue){ data = new char[strlen(initValue) + 1]; strcpy(data, initValue); } //StringValue类的构造函数 String::StringValue::StringValue(const char *initValue){ init(initValue); } //StringValue类的拷贝赋值运算符 String::StringValue::StringValue(const StringValue& rhs){ init(rhs.data); } //StringValue类的析构函数 String::StringValue::~StringValue(){ delete[] data; } //String实现代码 //String类的构造函数 String::String(const char *initValue) : value(new StringValue(initValue)) {} //重载[]运算符,针对const Strings const char& String::operator[](int index) const{ return value->data[index]; } //重载[]运算符,针对non-const Strings char& String::operator[](int index){ if (value->isShared()) { value = new StringValue(value->data); } value->markUnshareable(); return value->data[index]; } //返回引用计数 int String::getRefCount(){ return value->getRefCount(); } //重载>>运算符 std::istream& operator>>(std::istream& is, const String& str){ is >> str.value->data; return is; } //重载<<运算符 std::ostream& operator<<(std::ostream& os, const String& str){ os << str.value->data; return os; } #endif //main.cpp #include"String.h" #include<iostream> using namespace std; int main(){ String str1("hello world"); String str2 = str1;//调用拷贝构造函数 String str3;//调用默认构造函数 str3 = str2;//调用拷贝赋值运算符 cout << "str1的引用计数是:" << str1.getRefCount() << endl; // 3 cout << "str2的引用计数是:" << str2.getRefCount() << endl; // 3 cout << "str3的引用计数是:" << str3.getRefCount() << endl; // 3 str1[0] = 'H';//调用针对non-const Strings的重载[]运算符 cout << str1 << endl; //"Hello world" cout << str2 << endl;//"hello world" cout << str3 << endl;//"hello world" cout << "str1的引用计数是:" << str1.getRefCount() << endl;//1 cout << "str2的引用计数是:" << str2.getRefCount() << endl;//2 cout << "str3的引用计数是:" << str3.getRefCount() << endl;//2 system("pause"); return 0; }
上述实现的String类的数据结构如下:
和上一个用dumbpointers实现的String类比较:第一,这个版本精简了许多,因为RCPtr类做掉了许多原本落在String身上的引用计数杂务;第二,智能指针几乎毫无间隙地取代了dumb pointer。
四、将引用计数加到既有的类身上
//RCObject.h #ifndef RCOBJECT_H #define RCOBJECT //引用计数基类 class RCObject{ public: void addReference();//增加引用计数 void removeReference();//减少引用计数,如果变为0,销毁对象 void markUnshareable();//将追踪其值是否可共享的成员设为false bool isShareable() const;//判断其值是否可共享 bool isShared() const;//判断其值是否正在被共享 int getRefCount();//返回引用计数 protected: RCObject();//构造函数 RCObject(const RCObject& rhs);//拷贝构造函数 RCObject& operator=(const RCObject& rhs);//拷贝赋值运算符 virtual ~RCObject() = 0;//析构函数 private: int refCount;//保存引用计数 bool shareable;//保存其值是否可共享的状态 }; //构造函数,这里refCount设为0,让对象创建者自行或将refCoun设为1 RCObject::RCObject(void) :refCount(0), shareable(true){} //拷贝构造函数,总是将refCount设为0,因为正在产生一个新对象,只被创建者引用 RCObject::RCObject(const RCObject&) : refCount(0), shareable(true){} //拷贝赋值运算符,这里只返回*this,因为左右两方RCObject对象的外围对象个数不受影响 RCObject& RCObject::operator=(const RCObject& rhs){ return *this; } //析构函数 RCObject::~RCObject(){} //增加引用计数 void RCObject::addReference(){ ++refCount; } //减少引用计数,如果变为0,销毁对象 void RCObject::removeReference(){ if (--refCount == 0) delete this; } //将追踪其值是否可共享的成员设为false void RCObject::markUnshareable(){ shareable = false; } //判断其值是否可共享 bool RCObject::isShareable() const{ return shareable; } //判断其值是否正在被共享 bool RCObject::isShared() const{ return refCount>1; } //返回引用计数 int RCObject::getRefCount(){ return refCount; } #endif //RCIPtr.h #ifndef RCIPTR_H #define RCIPTR_H #include "RCObject.h" //智能指针模板类,用来自动执行引用计数类成员的操控动作 template<typename T> class RCIPtr{ public: RCIPtr(T* realPtr = 0);//构造函数 RCIPtr(const RCIPtr& rhs);//拷贝构造函数 ~RCIPtr();//析构函数 RCIPtr& operator=(const RCIPtr& rhs);//拷贝赋值运算符 const T* operator->() const;//重载->运算符 T* operator->();//重载->运算符 const T& operator*() const;//重载*运算符 T& operator*();//重载*运算符 private: struct CountHolder :public RCObject{ ~CountHolder() { delete pointee; } T* pointee; }; CountHolder* counter; void init();//初始化操作 void makeCopy();//copy-on-write中的copy部分 }; //共同的初始化操作 template <typename T> void RCIPtr<T>::init(){ if (counter->isShareable() == false){ T* oldValue = counter->pointee; counter = new CountHolder; counter->pointee = new T(*oldValue); } counter->addReference(); } //构造函数 template <typename T> RCIPtr<T>::RCIPtr(T* realPtr) :counter(new CountHolder){ counter->pointee = realPtr; init(); } //拷贝构造函数 template <typename T> RCIPtr<T>::RCIPtr(const RCIPtr& rhs) :counter(rhs.counter){ init(); } //析构函数 template <typename T> RCIPtr<T>::~RCIPtr(){ counter->removeReference(); } //拷贝赋值运算符 template <typename T> RCIPtr<T>& RCIPtr<T>::operator=(const RCIPtr& rhs){ if (counter != rhs.counter){ counter->removeReference(); counter = rhs.counter; init(); } return *this; } //重载->运算符,const版本 template<typename T> const T* RCIPtr<T>::operator->() const { return counter->pointee; } //重载*运算符,non-const版本 template<typename T> const T& RCIPtr<T>::operator*() const { return *(counter->pointee); } //copy-on-write中的copy部分 template <typename T> void RCIPtr<T>::makeCopy(){ if (counter->isShared()){ T* oldValue = counter->pointee; counter->removeReference(); counter = new CountHolder; counter->pointee = new T(*oldValue); counter->addReference(); } } //重载->运算符,non-const版本 template <typename T> T* RCIPtr<T>::operator->(){ makeCopy(); return counter->pointee; } //重载*运算符,non-const版本 template <typename T> T& RCIPtr<T>::operator*(){ makeCopy(); return *(counter->pointee); } #endif //Widget.h #ifndef WIDGET_H #define WIDGET_H #include <iostream> class Widget{ public: Widget(int s = 0) :size(s){} Widget(const Widget& rhs) { size = rhs.size; } ~Widget(void) {} Widget& operator=(const Widget& rhs){ if (this == &rhs) return *this; this->size = rhs.size; return *this; } void doThis() { std::cout << "doThis()" << std::endl; } int showThat() const { std::cout << "showThat()" << std::endl; return size; } private: int size; }; #endif //RCWidget.h #ifndef RCWIDGET_H #define RCWIDGET_H #include "RCIPtr.h" #include "Widget.h" class RCWidget{ public: RCWidget(int size = 0) :value(new Widget(size)){} ~RCWidget() {} void doThis() { value->doThis(); } int showThat() const { return value->showThat(); } private: RCIPtr<Widget> value; }; #endif //main.cpp #include"RCWidget.h" using namespace std; int main(){ RCWidget rc1(5); rc1.doThis(); cout << rc1.showThat() << endl; RCWidget rc2(rc1); rc2.doThis(); cout << rc2.showThat() << endl; system("pause"); return 0; }
上述例子的数据结构如下:
RCIRtr和RCPtr之间有两个差异:第一,RCPtr对象直接指向实值,而RCIPtr对象通过中间层CountHolder对象指向实值;第二,RCIPtr将operator->和operator*重载了,这样只要有non-const access发生于被指物身上,copy-on-write就会自动执行。
总结:引用计数的实现需要成本。每一个拥有计数能力的实值都有一个引用计数器,而大部分操作都需要能够以某种方式检查或处理这个引用计数器,因此对象的实值需要更多内存。而且引用计数的底层源代码比没有引用计数的复杂的多。
引用计数是个优化计数,其适用前提是对象常常共享实值。使用引用计数改善效率的时机有以下两个:第一,相对多数的对象共享相对少量的实值;第二,对象实值的产生或销毁成本很高,或是它们使用许多内存。