您的位置:首页 > 编程语言 > C语言/C++

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提供了带引用计数的基类的方法来解决这些问题——通过构建一个智能指针类来代理原始类,

带引用计数基类的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;
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息