
More Effective C++之引用计数
发布时间:2006-07-31 10:28:45 来源:BLOG 网友评论 0 条
Reference counting让我想起了Java,当如果想用C++来实现Java的能力的话,那Reference counting必不可少。Reference counting可以节省程序的运行成本,大量的构造、析构、分配、释放和拷贝的代价被省略。
实现
这是Meyers给出的String的实现,然而我的观点是如果没有特别的必要的话,对stirng最好不要使用引用计数,因为在多线程程序中同步的代价要大于引用计数本身的好处,得不偿失。
如果StringValue是一个现成的类,无法修改它的实现,那怎么办?没关系可以用委托,下面是一个典型的实现:
评估
实现引用计数是需要有前提的,不是所有的情况下,使用引用计数都是合适的。适合情况如下:
相对多的对象共享相对少量的实值。
对象的实值产生或者销毁的成本很高,或者占用很多内存。
但是要记住,即使是Java也会有内存泄漏,不要指望小小的引用计数(上面简单的实现)不会产生同样的问题。
引用计数是一项很深奥的技术,想想Java,所以需要很谨慎的对待,但愿它能带来程序设计上的优化。
实现
| classRCObject { public: RCObject():refCount(0),shareable(true){} RCObject(constRCObject&):refCount(0),shareable(true){} RCObject& operator=(constRCObject& rhs){return *this;} virtual ~RCObject()=0; void AddReference(){++refCount;} void RemoveReference(){if (--refCount == 0) deletethis;} void markUnshareable(){shareable = false;} bool isShareable() const{returnshareable;} bool isShared() const {returnrefCount > 1;} private: int refCount; bool shareable; }; RCObject::~RCObject(){} template <classT> class RCPtr { public: RCPtr(T* realPtr = 0):pointee(realPtr){init();} RCPtr(constRCPtr& rhs):pointee(rhs.pointee){init();} ~RCPtr(){if (pointee) pointee->RemoveReference();} RCPtr& operator = (constRCPtr& rhs) { if (pointee!=rhs.pointee) { if (pointee) pointee->RemoveReference(); pointee = rhs.pointee; init(); } return *this; } T* operator->() const { returnpointee;} T& operator*() const{return *pointee;} private: T* pointee; void init() { if (pointee == 0) return; if (pointee->isShareable() == false) pointee = newT(*pointee); pointee->AddReference(); } }; class String { public: String(const char* value = ""):value(newStringValue(value)){} const char& operator[](intnIndex) const { return value->data[nIndex]; } char& operator[](intnIndex) { if (value->isShared()) value = newStringValue(value->data); value->markUnshareable(); returnvalue->data[nIndex]; } protected: private: struct StringValue:publicRCObject { char* data; String Value(constchar* initValue) { init(initValue); } String Value(constStringValue& rhs) { init(rhs.data); } void init(constchar * initValue) { data = newchar[strlen(initValue) + 1]; strcpy(data,initValue); } ~String Value() { delete [] data; } }; RCPtr<StringValue> value; }; |
这是Meyers给出的String的实现,然而我的观点是如果没有特别的必要的话,对stirng最好不要使用引用计数,因为在多线程程序中同步的代价要大于引用计数本身的好处,得不偿失。
如果StringValue是一个现成的类,无法修改它的实现,那怎么办?没关系可以用委托,下面是一个典型的实现:
| classRCObject { public: RCObject():refCount(0),shareable(true){} RCObject(constRCObject&):refCount(0),shareable(true){} RCObject& operator=(constRCObject& rhs){return *this;} virtual ~RCObject()=0; void AddReference(){++refCount;} void RemoveReference(){if (--refCount == 0) deletethis;} void markUnshareable(){shareable = false;} bool isShareable() const{returnshareable;} bool isShared() const {returnrefCount > 1;} private: int refCount; bool shareable; }; RCObject::~RCObject(){} template<classT> class RCIPtr { public: RCIPtr(T* realPtr = 0):counter(new CountHolder) { counter->pointee = realPtr; init(); } RCIPtr(constRCIPtr& rhs):counter(rhs.counter) { init(); } ~RCIPtr() { counter->RemoveReference(); } RCIPtr& operator = (constRCIPtr& rhs) { if (counter != rhs.counter) { counter->RemoveReference(); counter = rhs.counter; init(); } return *this; } constT* operator->()const { returncounter->pointee; } T* operator->() { makeCopy(); returncounter->pointee; } constT& operator*() const { return *(counter->pointee); } T& operator*() { makeCopy(); return *(counter->pointee); } private: struct CountHolder:publicRCObject { ~Count Holder(){deletepointee;} T* pointee; }; Count Holder* counter; void init() { if (counter->isShareable() == false) { T* oldValue = counter->pointee; counter = newCountHolder; counter->pointee = newT(*oldValue); } counter->AddReference(); } void makeCopy() { if (counter->isShared()) { T* oldValue = counter->pointee; counter->RemoveReference(); counter = newCountHolder; counter->pointee = newT(*oldValue); counter->AddReference(); } } }; class Widget { public: Widget(intSize){} Widget(constWidget& rhs){} ~Widget(){} Widget operator=(const Widget& rhs){} void doThis(){printf("doThis()/n");return;} int showThat() const{printf("showThat()/n"); return 0;} protected: private: inti; }; class RCWidget { public: RCWidget(intsize):value(newWidget(size)){} void doThis(){value->doThis();} int showThat()const {returnvalue->showThat();} protected: private: RCIPtr<Widget> value; }; |
评估
实现引用计数是需要有前提的,不是所有的情况下,使用引用计数都是合适的。适合情况如下:
相对多的对象共享相对少量的实值。
对象的实值产生或者销毁的成本很高,或者占用很多内存。
但是要记住,即使是Java也会有内存泄漏,不要指望小小的引用计数(上面简单的实现)不会产生同样的问题。
引用计数是一项很深奥的技术,想想Java,所以需要很谨慎的对待,但愿它能带来程序设计上的优化。
推荐阅讯
- C++ Builder2006控件的安装方法
- 理解c++面向对象程序设计中的抽象理论
- c/c++中结构体(struct)知识点强化,链表的学
- C++类的分解,抽象类与纯虚函数的需要性
- C/C++中多维数组的指针作为函数参数传递!
- Windows Sockets:阻塞
- C/C++作用域引申出的编码规范
- C/C++中数组和指针类型的关系的入门教程
- 最常见的20种VC++编译错误信息
- 从C++到Java --理解面向对象是关键所在
阅读排行
- 1.Borland 发布C++ Builder 2006 RAD 环境
- 2.C/C++程序员应聘常见面试题深入剖析
- 3.Visual C++常用数据类型转换详解
- 4.C++中的 static 关键字
- 5.利用VC++实现局域网实时视频传输
- 6.浅谈C/C++内存泄漏及其检测工具
- 7.英国投票否决C++/CLI 微软强攻ISO标准受挫
- 8.VC++下用MSComm控件实现串口通讯
- 9.伪随机数生成及在VC++中的实现
- 10.VC++编程实现对波形数据的频谱分析
专题教程
- 大话G游 专题:手机病毒揭密
- ARP攻击防范与解决方案 路由故障处理手册
- Picasa中文版_Picasa教程 专题:清除流氓软件
- Firefox专题 seo搜索引擎优化专区
- 重装Windows必知的事情 装机之必备软件大行动
病毒专杀栏
