使用引用计数的类

    我们可以使用这句格言:计算机科学中的绝大部分问题都可以通过增加一个中间层次来解决。我们增加一个
新类CountHolder以处理引用计数,它从RCObject继承。我们让CountHolder包含一个指针指向Widget,将CountHolder

类指针封装在智能指针RCIPtr(名字中的"i"表示间接"indirect")内。设计图如下:


一、带引用计数的基类
RCObject的定义如下:

class RCObject
{
public:
	RCObject();
	RCObject(const RCObject& rhs);
	RCObject& operator=(const RCObject& rhs);
	virtual ~RCObject() = 0;
	
	void addReference();
	void removeReference();
	
	void markUnshareavle();
	bool isShareable() const;
	bool isShared() const;
	
private:
	int refCount;	// 引用计数
	bool shareable;	// 是否共享的标志
};


RCObject的实现代码:
RCObject::RCObject() : refCount(0), shareable(true) {}
RCObject::RCObject(const RCObject&) : refCount(0), shareable(true) {}
RCObject& RCObject::operator=(const RCObject&) { return *this; }
RCObject::~RCObject() {}	// 纯虚析构函数必须实现,即使是纯虚的不用干什么事

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; }

二、在现存类上增加引用计数
RCIPtr的实现如下:
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();
};

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;
}

// 实现copy-on-write(COW)的拷贝部分
template<class T>
void RCIPtr<T>::makeCopy()
{
	if(counter->isShared())
	{
		T* oldValue = conter->pointee;
		counter->removeReference();
		counter = new CountHolder;
		counter->pointee = new T(*oldValue);
		counter->addReference();
	}
}

// const访问,不需要写时复制
template<class T>
const T* RCIPtr<T>::operator->() const
{
	return counter->pointee;
}

// 非const访问,需要写时复制
template<class T>
T* RCIPtr<T>::operator->()
{
	makeCopy();
	return counter->pointee;
}

// const访问,不需要写时复制
template<class T>
const T& RCIPtr<T>::operator*() const
{
	return *(counter->pointee);
}

// 非const访问,需要写时复制
template<class T>
T& RCIPtr<T>::operator*()
{
	makeCopy();
	return *(counter->pointee);
}
    RCIPtr重载了operator->和operator*,当有对被指向的对象的非const的操作时,写时拷贝自动执行。


    有了RCIPtr,很容易实现RCWidget,因为RCWidget的每个函数都是将调用传递给RCIPtr以操作Widget对象。
举个例子,如果Widget是这样的:

class Widget
{
public:
	Widget(int size);
	Widget(const Widget& rhs);
	~Widget();
	Widget& operator=(const Widget& rhs);
	void doThis();
	int showThat() const;
};


那么RCWidget将被定义为这样:
class RCWidget
{
public:
	RCWidget(int size) : value(new Widget(size)) {}
	void doThis() { value->doThis(); }
	int showThat() const { return value->showThat(); }
private:
	RCIPtr<Widget> value;
};

    1)引用计数在下列情况对提高效率有用:
    少量的值被大量的对象共享。这样的共享通常通过调用赋值操作和拷贝构造而发生。对象/值的比例越高,
越是适宜使用引用计数。使用profiler或其他工具分析是否创建和销毁值的行为是性能瓶颈,并能得出对象/值
的比例。
    2)有些数据结构(如有向图)将导致自我引用或环状结构。这样的数据结构可能导致孤立的自引用对象,它没有
被别人使用,而其引用计数又绝不会降到零。因为这个无用的结构中的每个对象被同结构中的至少一个对象所引用。
商业化的垃圾收集体系使用特别的技术来查找这样的结构并消除它们。
    3)使用引用计数可以不用担心谁去执行删除操作。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值