more effective c++——Item M29 引用计数(三)带引用计数的基类的实现
2017-05-05 00:44
453 查看
more effective c++——Item M29 引用计数(一)和more effective c++——Item M29 引用计数(二)这两篇都是针对char *的实现,虽然能够正常工作,但是存在以下问题:
1.用户类仍然需要构造自己的数据结构,并对值、计数器进行操作
2.不便于移植,需要对原始的类做特定的修改,不同的数据类型需要重新设计
3.必须要有权限修改数据类的源代码,如果该类存在于lib中,则无法实现
是否可以设计一种新的类,达到引用计数的效果的同时避免上述问题,并且对用户屏蔽该类的实现?stanly lippman提供了带引用计数的基类的方法来解决这些问题——通过构建一个智能指针类来代理原始类,
RCObject类实现如下:
1.原始指针作为参数的构造函数
2.由于持有堆内存上的对象,因此需要实现拷贝构造函数与赋值操作符
3.析构函数,负责根据引用计数的值判断是否需要删除堆上的资源
4.提供operator->与operator*操作符,用于模拟指针操作
5.为了不限于为某一类型提供服务,实现为模板类,且其模板类型必须从rcobject继承
实现如下:
有了引用计数的基类及智能指针,以前实现的stringvalue则不再需要持有rfcount,只需要从它继承,然后持有必要的资源,让rcptr负责引用计数与构造析构相关的工作即可,以下为stringvalue及String类的实现:
RCIPtr的使用:
1.用户类仍然需要构造自己的数据结构,并对值、计数器进行操作
2.不便于移植,需要对原始的类做特定的修改,不同的数据类型需要重新设计
3.必须要有权限修改数据类的源代码,如果该类存在于lib中,则无法实现
是否可以设计一种新的类,达到引用计数的效果的同时避免上述问题,并且对用户屏蔽该类的实现?stanly lippman提供了带引用计数的基类的方法来解决这些问题——通过构建一个智能指针类来代理原始类,
带引用计数基类的String类
一.构建引用计数的基类RCObject
1.RCObject作为引用计数的基类,所有的引用计数类都从它继承 2.RCObject只提供基本的操作,但是不对计数器及资源做任何操作 3.RCObject提供该对象是否可共享的标记符,并提供相应操作接口,RCObject对象默认可共享 4.作为基类为了实现动态绑定,RCObject需要作为纯虚类实现,不可实例化 5.RCObject为了能够在引用计数为0的时候删除资源,必须调用delete this,则RCObject子类必须建立在堆上 6.当构造一个RCObject子类时,我们并不知道子类要如何设置引用计数,因此我们将RCObject初始化引用计数为0,并由持有rcobject子类的类去负责引用计数的增减及资源的释放
RCObject类实现如下:
#pragma once class RCObject { public: RCObject(); RCObject(const RCObject& rhs); RCObject& operator=(const RCObject& rhs); virtual ~RCObject() = 0; void addReference(); void removeReference(); void markUnshareable(); bool isShareable() const; bool isShared() const; private: int refCount; bool shareable; }; RCObject::RCObject() : refCount(0), shareable(true) {} RCObject::RCObject(const RCObject&) : refCount(0), shareable(true) {} RCObject& RCObject::operator=(const RCObject&) { return *this; } RCObject::~RCObject() {} // virtual dtors must always // be implemented, even if // they are pure virtual // and do nothing (see also // Item M33 and Item E14) void RCObject::addReference() { ++refCount; } void RCObject::removeReference() { if (--refCount == 0) delete this; } void RCObject::markUnshareable() { shareable = false; } bool RCObject::isShareable() const { return shareable; } bool RCObject::isShared() const { return refCount > 1; }
RCPtr 的实现
有了引用计数的基类,可以开始着手实现持有rcobject对象的类了,该类负责引用计数的增减及对象的构造与释放,它相当于一个简易的智能指针,主要实现以下功能:1.原始指针作为参数的构造函数
2.由于持有堆内存上的对象,因此需要实现拷贝构造函数与赋值操作符
3.析构函数,负责根据引用计数的值判断是否需要删除堆上的资源
4.提供operator->与operator*操作符,用于模拟指针操作
5.为了不限于为某一类型提供服务,实现为模板类,且其模板类型必须从rcobject继承
实现如下:
#pragma once // template class for smart pointers-to-T objects. T must // support the RCObject interface, typically by inheriting from RCObject template<class T> class RCPtr { public: RCPtr(T* realPtr = 0); RCPtr(const RCPtr& rhs); ~RCPtr(); RCPtr& operator=(const RCPtr& rhs); T* operator->() const; // see Item 28 T& operator*() const; // see Item 28 private: T *pointee; // dumb pointer this object is emulating void init(); // common initialization }; template<class T> RCPtr<T>::RCPtr(T* realPtr) : pointee(realPtr) { init(); } template<class T> RCPtr<T>::RCPtr(const RCPtr& rhs) : pointee(rhs.pointee) { init(); } template<class T> void RCPtr<T>::init() { if (pointee == 0) { return; } if (pointee->isShareable() == false) { pointee = new T(*pointee); } pointee->addReference(); } template<class T> RCPtr<T>& RCPtr<T>::operator=(const RCPtr& rhs) { if (pointee != rhs.pointee) { if (pointee) { pointee->removeReference(); // remove reference } pointee = rhs.pointee; init(); } return *this; } template<class T> RCPtr<T>::~RCPtr() { if (pointee)pointee->removeReference(); } template<class T> T* RCPtr<T>::operator->() const { return pointee; } template<class T> T& RCPtr<T>::operator*() const { return *pointee; }
有了引用计数的基类及智能指针,以前实现的stringvalue则不再需要持有rfcount,只需要从它继承,然后持有必要的资源,让rcptr负责引用计数与构造析构相关的工作即可,以下为stringvalue及String类的实现:
#pragma once #include "RCObject.h" #include "RCPtr.h" #include <cstring> class String { // class to be used by application developers public: String(const char *value = ""); const char& operator[](int index) const; char& operator[](int index); private: // class representing string values struct StringValue : public RCObject { char *data; StringValue(const char *initValue); StringValue(const StringValue& rhs); void init(const char *initValue); ~StringValue(); }; RCPtr<StringValue> value; }; void String::StringValue::init(const char *initValue) { data = new char[strlen(initValue) + 1]; strcpy(data, initValue); } String::StringValue::StringValue(const char *initValue) { init(initValue); } String::StringValue::StringValue(const StringValue& rhs) { init(rhs.data); } String::StringValue::~StringValue() { delete[] data; } String::String(const char *initValue) : value(new StringValue(initValue)) {} const char& String::operator[](int index) const { return value->data[index]; } char& String::operator[](int index) { if (value->isShared()) { value = new StringValue(value->data); } value->markUnshareable(); return value->data[index]; }
通用引用计数的实现
上面的类针必须要能够修改原始代码,在不可修改原始代码的情况下,增加一个中间层即可实现同样的功能,而且使用起来更加方便,因为类的相关信息都被屏蔽,新实现的类不需要关心以何种结构来承载资源与引用计数 计算机科学中的绝大部分问题都可以通过增加一个中间层次来解决。由于不能直接修改原始类——OldClass的代码,可以通过增加一个中间层CountHolder ,让它持有需要修改的类的指针,然后让智能指针类RCIPtr的模板对象持有该计数器的指针,然后将RCIPtr<OldClass>作对象为新实现的引用计数类RFNewClass的成员变量,通过RFNewClass间接持有的OldClass指针实现与OldClass相同的接口即可。
//RCIPtr.hpp实现, #pragma once #include "RCObject.h" template<class 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(); // see below }; template<class T> void RCIPtr<T>::init() { if (counter->isShareable() == false) { T *oldValue = counter->pointee; counter = new CountHolder; counter->pointee = new T(*oldValue); } counter->addReference(); } template<class T> RCIPtr<T>::RCIPtr(T* realPtr) : counter(new CountHolder) { counter->pointee = realPtr; init(); } template<class T> RCIPtr<T>::RCIPtr(const RCIPtr& rhs) : counter(rhs.counter) { init(); } template<class T> RCIPtr<T>::~RCIPtr() { counter->removeReference(); } template<class T> RCIPtr<T>& RCIPtr<T>::operator=(const RCIPtr& rhs) { if (counter != rhs.counter) { counter->removeReference(); counter = rhs.counter; init(); } return *this; } template<class T> // implement the copy void RCIPtr<T>::makeCopy() // part of copy-on- { // write (COW) if (counter->isShared()) { T *oldValue = counter->pointee; counter->removeReference(); counter = new CountHolder; counter->pointee = new T(*oldValue); counter->addReference(); } } template<class T> // const access; const T* RCIPtr<T>::operator->() const // no COW needed { return counter->pointee; } template<class T> // non-const T* RCIPtr<T>::operator->() // access; COW { makeCopy(); return counter->pointee; } // needed template<class T> // const access; const T& RCIPtr<T>::operator*() const // no COW needed { return *(counter->pointee); } template<class T> // non-const T& RCIPtr<T>::operator*() // access; do the { makeCopy(); return *(counter->pointee); }
RCIPtr的使用:
#pragma once #include "RCIPtr.h" #include <string> using namespace std; class RCString { public: RCString(const char *str = "") : value(new string(str)) {} private: RCIPtr<string> value; };
相关文章推荐
- more effective c++——Item M29 引用计数(二)带静态成员变量的rfstring类实现
- 【转载】引用计数(More Effective c++ Item M29)
- more effective c++——Item M29 引用计数(一)简略的rfstring类设计和写时拷贝
- (大卫的阅读笔记)More Effective C++ Item 附2:一个auto_ptr的实现实例
- more effective c++--引用计数
- More Effective C++ Item 附2:一个auto_ptr的实现实例
- 《More Effective C++》 Item M1:指针与引用的区别
- 《more effective c++》Item M1:指针与引用的区别
- More Effective C# Item7 : 不要为基类或者接口创建泛型的特殊实现
- more effective c++之Item M1:指针与引用的区别
- more effective c++——Item M30 代理类(一)多维数组的实现
- More Effective C++ 读书摘要(auto_ptr的一个实现)
- More Effective C++:指针与引用的区别
- 《more effective c++》Item M3:不要对数组使用多态
- More Effective C++:指针与引用的区别
- Item 2:Prefer C++-style casts.(More Effective C++)
- More Effective C++:指针与引用的区别
- c/C++编译的程序占用的内存以及More Effective C++ 条款1:指针与引用的区别
- More Effective C++:通过引用捕获异常
- More Effective C++ 读书摘要(三、异常)Item9 - 15