主要参考《提高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;
}