More Effective C++之引用计数

王朝c/c++·作者佚名  2008-06-01
宽屏版  字体: |||超大  

Reference counting让我想起了Java,当假如想用C++来实现Java的能力的话,那Reference counting必不可少。Reference counting可以节省程序的运行成本,大量的构造、析构、分配、释放和拷贝的代价被省略。

实现

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,所以需要很谨慎的对待,但愿它能带来程序设计上的优化。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
© 2005- 王朝网络 版权所有