分享
 
 
 

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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有