More Effective C++之29
来源:互联网 发布:软件项目工作量估算 编辑:程序博客网 时间:2024/06/12 23:13
条款29:Reference counting(引用计数)
Reference counting让我想起了Java,当如果想用C++来实现Java的能力的话,那Reference counting必不可少。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;
voidAddReference(){++refCount;}
voidRemoveReference(){if (--refCount == 0) deletethis;}
voidmarkUnshareable(){shareable = false;}
boolisShareable() const{returnshareable;}
boolisShared() const {returnrefCount > 1;}
private:
intrefCount;
boolshareable;
};
RCObject::~RCObject(){}
template <classT>
classRCPtr
{
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;
voidinit()
{
if (pointee == 0)
return;
if (pointee->isShareable() == false)
pointee = newT(*pointee);
pointee->AddReference();
}
};
classString
{
public:
String(constchar* value = ""):value(newStringValue(value)){}
constchar& operator[](intnIndex) const
{
returnvalue->data[nIndex];
}
char& operator[](intnIndex)
{
if (value->isShared())
value = newStringValue(value->data);
value->markUnshareable();
returnvalue->data[nIndex];
}
protected:
private:
structStringValue:publicRCObject
{
char* data;
StringValue(constchar* initValue)
{
init(initValue);
}
StringValue(constStringValue& rhs)
{
init(rhs.data);
}
voidinit(constchar * initValue)
{
data = newchar[strlen(initValue) + 1];
strcpy(data,initValue);
}
~StringValue()
{
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;
voidAddReference(){++refCount;}
voidRemoveReference(){if (--refCount == 0) deletethis;}
voidmarkUnshareable(){shareable = false;}
boolisShareable() const{returnshareable;}
boolisShared() const {returnrefCount > 1;}
private:
intrefCount;
boolshareable;
};
RCObject::~RCObject(){}
template<classT>
classRCIPtr
{
public:
RCIPtr(T* realPtr = 0):counter(newCountHolder)
{
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:
structCountHolder:publicRCObject
{
~CountHolder(){deletepointee;}
T* pointee;
};
CountHolder* counter;
voidinit()
{
if (counter->isShareable() == false)
{
T* oldValue = counter->pointee;
counter = newCountHolder;
counter->pointee = newT(*oldValue);
}
counter->AddReference();
}
voidmakeCopy()
{
if (counter->isShared())
{
T* oldValue = counter->pointee;
counter->RemoveReference();
counter = newCountHolder;
counter->pointee = newT(*oldValue);
counter->AddReference();
}
}
};
classWidget
{
public:
Widget(intSize){}
Widget(constWidget& rhs){}
~Widget(){}
Widgetoperator=(constWidget& rhs){}
voiddoThis(){printf("doThis()/n");return;}
intshowThat() const{printf("showThat()/n"); return 0;}
protected:
private:
inti;
};
classRCWidget
{
public:
RCWidget(intsize):value(newWidget(size)){}
voiddoThis(){value->doThis();}
intshowThat()const {returnvalue->showThat();}
protected:
private:
RCIPtr<Widget> value;
};
评估
实现引用计数是需要有前提的,不是所有的情况下,使用引用计数都是合适的。适合情况如下:
相对多的对象共享相对少量的实值。
对象的实值产生或者销毁的成本很高,或者占用很多内存。
但是要记住,即使是Java也会有内存泄漏,不要指望小小的引用计数(上面简单的实现)不会产生同样的问题。
引用计数是一项很深奥的技术,想想Java,所以需要很谨慎的对待,但愿它能带来程序设计上的优化。
- More Effective C++之29
- 《more effective c++》读书笔记
- More Effective C++(2)
- 《More Effective C++》读后感
- 《More Effective C++》笔记
- 《Effective C++》和《More Effective C++》汇总
- 《More Effective C++》读书笔记一
- 《more effective c++》笔记4
- More Effective C++:类型转换
- More Effective C++:类型转换
- More Effective C++:Item 27
- more effective c++--引用计数
- 读More Effective C++(1)
- More Effective C++:Item 27
- 《More Effective C++》读书笔记-异常
- 《More Effective C++》读书笔记-效率
- 《More Effective C++》读书笔记-技术
- 《More Effective C++》阅读记录
- MD5 Fingerprint 1.1
- Adware.Roogoo恶意广告程序的手动清除
- 第二届电商江湖会感想
- VB中的Unicode 和 Ansi 格式
- 关于那个计算器编译器的问题
- More Effective C++之29
- 从VB 6到VB.NET——窗体特殊应用
- FTP:文件传输协议(指令及响应代码)
- ORACLE 常用的SQL语法和数据对象
- 懂技术和不懂技术的人
- 动态从数据库中读值,静态给select后,再改变select的属性
- 开篇之述
- 加入.NET圈子带来的思考,什么是RSS?RSS能带给我们什么?
- 将ASP.NET页面内的数据导出到Excel 或 Word中