主要参考《提高C++性能的编程技术》第12章 引用计数
设计思路
1. rc.h中:
(1) 提供RCObject,内部封装了refCount及其基本加减操作;
(2) 提供RCPtr,是一个智能指针。普通的智能指针内部封装一个基本类型的指针,但这里的智能指针内部封装的是指向RCObject类型的指针。因此,这个智能指针可以根据RCObject维护的引用计数变量refCount来实现引用计数的优势,如:
“赋值时复用”:在赋值操作时,只用refCount++即可复用已经在堆上创建好的原有实例;
“自动释放”: 在引用计数refCount==0时,自动析构掉对象。
2. rc.cpp
使用引用计数时候,要做两件事情。
(1) 继承RCObject,以便拥有refCount及其基本加减操作。
class BigInt : public RCObject{
...
};
(2) 引用计数版本的BigInt——RCBigInt,内部封装BigInt的智能指针RCPtr<BigInt>,这样就可以“赋值时复用”和“自动释放”
class RCBigInt {
...
private:
RCPtr<BigInt> value;
};
引用计数的优缺点
结合代码,用脚趾头也能想明白上面设计的优缺点——
缺点:引用计数版本RCBigInt在创建时,由于又在内部套一个智能指针,又是创建refCount的,效率反而更慢;
优点:但是引用计数版本RCBigInt在赋值时,可以直接refCount++,就很快;并且refCount==0时,也不用手工去释放。
rc.h
#ifndef RC_H #define RC_H /* RCObject:引用计数类型的基类 */ class RCObject{ public: void addReference(){ ++refCount;} void removeReference(){ if(--refCount == 0){ delete this; } } void markUnshareable(){ shareable = false; } bool isShareable() const{ return shareable; } /* 可否共享 */ bool isShared() const {return refCount > 1; } /* 是否已经被共享 */ protected: RCObject():refCount(0), shareable(true){} RCObject(const RCObject& rhs):refCount(0), shareable(true){} RCObject& operator= (const RCObject& rhs){ return *this; } //? virtual ~RCObject(){} //?virtual private: int refCount; /* 引用计数 */ bool shareable; /* 可否共享 */ }; /* RCPtr:封装了"引用计数类型RCObject的指针"的"智能指针" (1) 智能指针: 本质上就是通过重载operator->和operator*操作符,在内部封装一个非智能指针的对象 (2) (支持引用计数的)智能指针: 内部封装的是一个 "指向RCObject类型的指针" 注:使用RCPtr<T>时保证,模板参数T是RCObject的子类 */ template<class T> class RCPtr{ public: RCPtr(T *realPtr = 0): pointee(realPtr) { addRef(); } //Ctor参数是 "指向RCObject类型的指针" RCPtr(const RCPtr& rhs): pointee(rhs.pointee) { addRef(); } //Ctor参数是 "指向RCObject类型的指针"的"智能指针" ~RCPtr(){ if(pointee) pointee->removeReference(); } T* operator-> () const {return pointee;} /* member access: operator-> */ T& operator* () const {return *pointee;} /* deference: operator* */ RCPtr& operator= (const RCPtr& rhs); /* operator= */ private: T *pointee; /* 指向RCObject类型的指针 */ void addRef(); /* 尝试本引用计数++ */ }; template<class T> void RCPtr<T>::addRef(){ if(0==pointee) return; if(false == pointee->isShareable()){//如果不能共享引用对象,则拷贝创建新的引用对象 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(); pointee=rhs.pointee; addRef(); } } #endif
rc.cpp
#include "rc.h" #include <iostream> #include <time.h> using namespace std; /* BigInt: 继承自RCObject,复用其引用计数的功能 注意:继承了RCObject,只是拥有了引用计数的facility(计数变量refCount),但并不能带来任何好处; 如果要用到引用计数的好处(赋值时避免复用以前堆中创建的),则必须同时用"智能指针"才行。 */ class BigInt : public RCObject{ friend BigInt operator+ (const BigInt&, const BigInt&); public: BigInt( const char *); BigInt( unsigned = 0); BigInt( const BigInt& ); BigInt& operator= (const BigInt&); BigInt& operator+= (const BigInt&); ~BigInt(); char *getDigits() const { return digits; } unsigned getNdigits() const{ return ndigits; } private: char *digits; /* 低char存放低十进制位, 每位以unsigned int形式存入char(而非ASCII码) */ unsigned ndigits; /* 十进制位# */ unsigned size; /* 容量 */ BigInt(const BigInt&, const BigInt&); /* operational Ctor */ //??? char fetch(unsigned i) const; }; BigInt::BigInt(const char *s){ if(s[0]=='\0'){ s="0"; //???对于0,统一成特殊情况'0'(ASCII码的'0')跟一个'\0'(即0) } size = ndigits = strlen(s); digits = new char[size]; for(unsigned i=0; i<ndigits; ++i){ digits[i] = s[ndigits-1-i] - '0'; } } BigInt::BigInt(unsigned u){ unsigned v=u; for(ndigits=1;(v/=10)>0;++ndigits); digits = new char[size=ndigits]; for(unsigned i=0;i<ndigits;++i){ digits[i]=u%10; u/=10; } } BigInt::BigInt(const BigInt& copyFrom){ size = ndigits = copyFrom.ndigits; digits = new char[size]; for(unsigned i=0; i<ndigits; ++i){ digits[i] = copyFrom.digits[i]; } } BigInt& BigInt::operator= (const BigInt& rhs){ if(this == &rhs) return *this; //如果size不够,则扩展char[] ndigits = rhs.ndigits; if(ndigits > size){ delete [] digits; digits = new char[size=ndigits]; } for(unsigned i=0; i<ndigits; i++){ digits[i] = rhs.digits[i]; } return *this; } BigInt& BigInt::operator+= (const BigInt& rhs){ //"必要时",size扩展到max unsigned max = 1 + (rhs.ndigits > ndigits ? rhs.ndigits : ndigits); if( size < max ){ char *d = new char[size=max]; for( unsigned i = 0; i<ndigits; ++i){ d[i] = digits[i]; } delete [] digits; digits = d; } //高位补0 while( ndigits < max){ digits[ ndigits++ ] = 0; } for(unsigned i=0; i<ndigits; ++i){ digits[i]+=rhs.fetch(i); if(digits[i]>=10){ digits[i]-=10; digits[i+1]++; } } if(digits[ndigits-1]==0){//最高位没有进位时 --ndigits; } return *this; } BigInt::~BigInt(){ delete [] digits; } BigInt::BigInt(const BigInt& left, const BigInt& right){ size = 1 + (left.ndigits > right.ndigits ? left.ndigits : right.ndigits); digits = new char[size]; ndigits = left.ndigits; for(unsigned i=0; i<ndigits; i++){ digits[i] = left.digits[i]; } *this += right; } inline char BigInt::fetch(unsigned i) const{ return i<ndigits ? digits[i] : 0 ; } /* 引用计数版本的BigInt——RCBigInt,内部封装智能指针RCPtr<BigInt>,这样就可以“赋值时复用”和“自动释放” */ class RCBigInt { friend RCBigInt operator+ (const RCBigInt&, const RCBigInt&); public: /*RCBigInt*/ RCBigInt (const char *p): value(new BigInt(p)){} RCBigInt (unsigned u=0): value(new BigInt(u)){} RCBigInt (const BigInt& bi): value(new BigInt(bi)){} private: RCPtr<BigInt> value; }; inline RCBigInt operator+ (const RCBigInt& left, const RCBigInt& right){ return RCBigInt( *(left.value) + *(right.value) ); } /*test assignment*/ void testBigIntAssign(int n){ //单纯继承了RCObject的BigInt只是拥有了refCount,但并不能够在赋值时复用曾经在堆中的对象,它和普通的类型效果一样 BigInt a, b, c; BigInt d = 1; time_t start = time(0); for(int i=0;i<n;++i){ a = b = c = d; //慢,∵每次在堆中创建新的 } time_t end = time(0); printf("%d\n", end-start); } void testRCBigIntAssign(int n){ //只有使用了"基于引用计数的智能指针RCPtr"以后,BigInt才能在赋值时复用曾经在堆中的对象 RCBigInt a, b, c; RCBigInt d = 1; time_t start = time(0); for(int i=0;i<n;++i){ a = b = c = d; //快,∵复用已经创建好的 } time_t end = time(0); printf("%d\n", end-start); } /*test creation*/ void testBigIntCreate(int n){ time_t start = time(0); for(int i=0;i<n;++i){ BigInt a = i; BigInt b = i+1; BigInt c = i+2; BigInt d = i+3; } time_t end = time(0); printf("%d\n", end-start); } void testRCBigIntCreate(int n){ time_t start = time(0); for(int i=0;i<n;++i){ RCBigInt a = i; RCBigInt b = i+1; RCBigInt c = i+2; RCBigInt d = i+3; } time_t end = time(0); printf("%d\n", end-start); } int main(){ testRCBigIntCreate(5000000); testBigIntCreate(5000000); testRCBigIntAssign(500000000); testBigIntAssign(500000000); system("pause"); return 0; }
相关推荐
C++引用计数设计与分析(解决垃圾回收问题).docx
引用计数的实现,c++源码实现,工程可编译,利用模板实现的,项目中可直接使用。部分代码是从webkit中引用计数直接引用过来的
一直以来都对智能指针一知半解,看C++Primer中也讲的不够清晰明白(大概是我功力不够吧)。近花了点时间认真看了智能指针,特地来写这篇文章。 智能指针是什么 简单来说,智能指针是一个类,它对普通指针进行...
COM入门学习实例,c++程序实现引用计数易于理解,动态绑定相关
C++实现 带引用计数的智能指针 VS2008工程文件
MyString 字符串类仿写_C++_(四种版本,引用计数,迭代器,加锁)
智能指针相信大家听说过吧,我理解的智能指针,既是一个C++模板类,重载了指针操作符...内部实现的关键在于:自动地址引用计数、操作符重载。 可以实现任意类型(基本数据类型、自定义类型)的指针地址的自动引用计数。
对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础...
对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数减至0,则删除对象),并增加右操作数所指对象的引用计数; 调用析构函数时,减少引用计数(如果引用计数减至0,则删除基础对象); ...
C++浅拷贝与深拷贝及引用计数分析 在C++开发中,经常遇到的一个问题就是与指针相关的内存管理问题,稍有不慎,就会造成内存泄露、内存破坏等严重的问题。不像Java一样,没有指针这个概念,所以也就不必担心与指针...
C++智能指针实现(包含拷贝构造,赋值函数,引用解引用重载) 帮助初学者掌握智能指针的实现原理,采用引用计数方式实现
该书介绍了C++编码规范以及编程过程中需要注意的地方,内容包括指针、引用、类型转换、运算符、异常、效率、引用计数、代理类以及虚函数等内容,是C++编程书籍中的经典之作。 有人这么形容这本书:程序员...
自己数据结构实习编的的c++多项式运算类,并且运用了引用计数的技巧!!
全面地描述了C++专家所使用的高级技术,包括placement new、虚构造函数、智能指针、引用计数、代理类和双重分派等。 本书主要特点:以实例说明异常处理从结构上及行为上给C++类和函数带来的巨大影响。 从...
它也记述了像 smart pointers(智能指针),reference counting(引用计数)和 proxy objects(代理对象)这样的重要的 C++ 编程技术。 Effective STL 像 Effective C++ 一样是一本面向指导方针的书,但是它专注于...
它也记述了像 smart pointers(智能指针),reference counting(引用计数)和 proxy objects(代理对象)这样的重要的 C++ 编程技术。 Effective STL 像 Effective C++ 一样是一本面向指导方针的书,但是它专注于...
第五章 对标准库的扩充:引用计数与智能指针 58 一、本节内容 58 二、 与引用计数 58 三、 59 四、 60 五、 62 总结 64 进一步阅读的参考资料 64 第六章 正则表达式库 66 一、本节内容 66 二、正则表达式...
2.3.1 引用计数 9 2.3.2 标记并清除 9 2.3.3 复制 9 2.3.4 采用哪种算法 9 2.3.5 实现垃圾回收器 10 2.3.6 是否使用多线程 10 2.3.7 何时回收垃圾 10 2.3.8 关于auto_ptr 11 2.4 一个简单的C++垃圾回收器 11 2.5 ...
条款29:Reference counting(引用计数) 183 条款30:Proxy classes(替身类、代理类) 213 条款31:让函数根据一个以上的对象型别来决定如何虚化 228 Making functions virtual with respect to more than one ...