【more effective c++读书笔记】【第5章】技术(5)——Reference counting(引用计数)(2)

来源:互联网 发布:python cmd命令 编辑:程序博客网 时间:2024/05/16 15:07

三、引用计数基类和智能指针实现的String类

//RCObject.h#ifndef RCOBJECT_H#define RCOBJECT//引用计数基类class RCObject{public:void addReference();//增加引用计数void removeReference();//减少引用计数,如果变为0,销毁对象void markUnshareable();//将追踪其值是否可共享的成员设为falsebool 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设为1RCObject::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;}//将追踪其值是否可共享的成员设为falsevoid 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 Stringschar& operator[](int index);//重载[]运算符,针对non-const Stringsint 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 Stringsconst char& String::operator[](int index) const{return value->data[index];}//重载[]运算符,针对non-const Stringschar& 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; // 3cout << "str2的引用计数是:" << str2.getRefCount() << endl; // 3cout << "str3的引用计数是:" << str3.getRefCount() << endl; // 3str1[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;//1cout << "str2的引用计数是:" << str2.getRefCount() << endl;//2cout << "str3的引用计数是:" << str3.getRefCount() << endl;//2system("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();//将追踪其值是否可共享的成员设为falsebool 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设为1RCObject::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;}//将追踪其值是否可共享的成员设为falsevoid 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就会自动执行。

总结:引用计数的实现需要成本。每一个拥有计数能力的实值都有一个引用计数器,而大部分操作都需要能够以某种方式检查或处理这个引用计数器,因此对象的实值需要更多内存。而且引用计数的底层源代码比没有引用计数的复杂的多。

引用计数是个优化计数,其适用前提是对象常常共享实值。使用引用计数改善效率的时机有以下两个:第一,相对多数的对象共享相对少量的实值;第二,对象实值的产生或销毁成本很高,或是它们使用许多内存。


1 0
原创粉丝点击