引用计数
引用计数说得直接点就是不同的对象内部共享同样的内容(内存),同时对象能够自己跟踪自己被引用多少次,能够在没有被继续引用的时候删除自己,保证了没有内存泄漏的出现。看起来貌似java里面的垃圾回收机制了。很多事物都有两面性,引用计数也不例外。看起来牛逼的东西必然有它的弱点,总有一些地方它比不过最原始的东西。
书上说了两种极端的情况,一种是大量的对象共享少数的相同的内容,一种是同样的内容只被共享少数几次,也就是基本没多少共享。显然前者是利用引用计数的典型情况。一般来说,下面的一些条件有利于引用计数的使用。比如说,目标对象消耗大量的资源;资源的分配和释放很昂贵;高度共享:由于使用复制构造函数和赋值操作符,所以引用计数可能比较大;引用的创建和清除相对低廉。如果程序中出现大量的对象创建和释放的操作,使用引用计数的效果反而会更差,而出现大量的对象的赋值操作则适合于引用计数的使用。
一般来说主要有两种实现方式。一种是你能够修改目标类的代码的情况,一种是你不能够得到目标类代码的情况。另外,还有给这些实现加上线程同步的情况。我分别实现了相关的代码,你也可以从提高c++性能的编程计数上面找到相关的代码。
情况1的类设计图如下,
从类设计图中可以看到要实现一个引用计数需要额外的三个类。RCObject是存储引用计数变量的基类,RCPtr是一个智能指针类,RCBigInt类里面包含一个RCPtr成员,该类相当于BigInt的代理类,和BigInt向外提供同样的接口。BigInt的实现稍微复杂了点,你也可以用任何简单的类替换它。
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
using namespace std;
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;
}
private:
int refCount;
bool shareable;
};
class BigInt : public RCObject
{
friend BigInt operator+(const BigInt&, const BigInt&);
public:
BigInt(const char*);
BigInt(unsigned u = 0);
BigInt(const BigInt&);
BigInt& operator=(const BigInt&);
BigInt& operator+=(const BigInt&);
~BigInt()
{
delete [] digits;
}
char* getDigits() const
{
return digits;
}
unsigned getNdigits() const
{
return ndigits;
}
private:
char* digits;
unsigned ndigits;
unsigned size;
BigInt(const BigInt&, const BigInt&);
char fetch(unsigned i) const
{
return i < ndigits ? digits[i] : 0;
}
};
BigInt::BigInt(const char* s)
{
if (s[0] == '\0')
{
s = "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; ++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)
{
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;
d = digits;
}
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(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 BigInt operator+(const BigInt& left, const BigInt& right)
{
return BigInt(left, right);
}
BigInt& BigInt::operator=(const BigInt& rhs)
{
if (this == &rhs) return *this;
ndigits = rhs.ndigits;
if (ndigits > size)
{
delete [] this;
digits = new char[size = ndigits];
}
for (unsigned i = 0; i < ndigits; ++i)
{
digits[i] = rhs.digits[i];
}
return *this;
}
ostream& operator<<(ostream& os, BigInt& bi)
{
char c;
const char* d = bi.getDigits();
for (int i = bi.getNdigits() - 1; i >= 0; --i)
{
c = d[i] + '0';
os << c;
}
os << endl;
return os;
}
template <typename T> class RCPtr
{
public:
RCPtr(T* realPtr = NULL) : pointee(realPtr) { Init(); }
RCPtr(const RCPtr& rhs) : pointee(rhs.pointee) { Init(); }
~RCPtr() { if (pointee) pointee->removeReference(); }
T* operator->() const { return pointee; }
T& operator*() const { return * pointee; }
RCPtr& operator=(const RCPtr& rhs);
private:
T* pointee;
void Init();
};
template <typename T> void RCPtr<T>::Init()
{
if (pointee == 0) return;
if (pointee->isShareable() == false)
{
pointee = new T(*pointee);
}
pointee->addReference();
}
template <typename T> RCPtr<T>& RCPtr<T>::operator=(const RCPtr& rhs)
{
if (pointee != rhs.pointee)
{
if (pointee) pointee->removeReference();
pointee = rhs.pointee;
Init();
}
return *this;
}
class RCBigInt
{
friend RCBigInt operator+(const RCBigInt&, const RCBigInt&);
public:
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));
}
void TestBigIntCreate(int n)
{
printf("TestBigIntCreate:%d\n", n);
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
BigInt a = i;
BigInt b = i + 1;
BigInt c = i + 2;
BigInt d = i + 3;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
void TestRCBigIntCreate(int n)
{
printf("TestRCBigIntCreate:%d\n", n);
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
RCBigInt a = i;
RCBigInt b = i + 1;
RCBigInt c = i + 2;
RCBigInt d = i + 3;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
void TestBigIntAssign(int n)
{
printf("TestBigIntAssign:%d\n", n);
BigInt a, b, c, d;
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
a = b = c = d;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
void TestRCBigIntAssign(int n)
{
printf("TestRCBigIntAssign:%d\n", n);
RCBigInt a, b, c, d;
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
a = b = c = d;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
int main()
{
const int NUM = 1000000;
TestBigIntCreate(NUM);
TestRCBigIntCreate(NUM);
TestBigIntAssign(NUM);
TestRCBigIntAssign(NUM);
return 0;
}
运行结果:
情况2的类设计图如下所示,
从图中可以看到,由于无法修改BigInt的实现,引入了一个新类CounterHolder作为引用计数的中间类。该类继承自RCObject,智能指针类RCIPtr包含一个CounterHolder的指针,而CounterHolder里面才包含一个BigInt的指针。这就相当于多了一次间接操作,因此在RCIBigInt的创建和删除操作中会增加时间,这可以从运行结果中可以看到。
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
using namespace std;
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;
}
private:
int refCount;
bool shareable;
};
class BigInt
{
friend BigInt operator+(const BigInt&, const BigInt&);
public:
BigInt(const char*);
BigInt(unsigned u = 0);
BigInt(const BigInt&);
BigInt& operator=(const BigInt&);
BigInt& operator+=(const BigInt&);
~BigInt()
{
delete [] digits;
}
char* getDigits() const
{
return digits;
}
unsigned getNdigits() const
{
return ndigits;
}
private:
char* digits;
unsigned ndigits;
unsigned size;
BigInt(const BigInt&, const BigInt&);
char fetch(unsigned i) const
{
return i < ndigits ? digits[i] : 0;
}
};
BigInt::BigInt(const char* s)
{
if (s[0] == '\0')
{
s = "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; ++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)
{
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;
d = digits;
}
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(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 BigInt operator+(const BigInt& left, const BigInt& right)
{
return BigInt(left, right);
}
BigInt& BigInt::operator=(const BigInt& rhs)
{
if (this == &rhs) return *this;
ndigits = rhs.ndigits;
if (ndigits > size)
{
delete [] this;
digits = new char[size = ndigits];
}
for (unsigned i = 0; i < ndigits; ++i)
{
digits[i] = rhs.digits[i];
}
return *this;
}
ostream& operator<<(ostream& os, BigInt& bi)
{
char c;
const char* d = bi.getDigits();
for (int i = bi.getNdigits() - 1; i >= 0; --i)
{
c = d[i] + '0';
os << c;
}
os << endl;
return os;
}
template <typename T> class RCIPtr
{
public:
RCIPtr(T* realPtr = NULL) : counter(new CountHolder)
{
counter->pointee = realPtr;
Init();
}
RCIPtr(const RCIPtr& rhs) : counter(rhs.counter) { Init(); }
~RCIPtr() { if (counter) counter->removeReference(); }
T* operator->() const { return counter->pointee; }
T& operator*() const { return *(counter->pointee); }
RCIPtr& operator=(const RCIPtr& rhs);
private:
struct CountHolder : public RCObject
{
~CountHolder() { delete pointee; }
T* pointee;
};
CountHolder* counter;
void Init();
};
template <typename T> void RCIPtr<T>::Init()
{
if (counter == 0) return;
if (counter->isShareable() == false)
{
counter = new CountHolder;
counter->pointee = new T(*counter->pointee);
}
counter->addReference();
}
template <typename T> RCIPtr<T>& RCIPtr<T>::operator=(const RCIPtr& rhs)
{
if (counter != rhs.counter)
{
if (counter) counter->removeReference();
counter = rhs.counter;
Init();
}
return *this;
}
class RCBigInt
{
friend RCBigInt operator+(const RCBigInt&, const RCBigInt&);
public:
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:
RCIPtr<BigInt> value;
};
inline RCBigInt operator+(const RCBigInt& left, const RCBigInt& right)
{
return RCBigInt(*(left.value) + *(right.value));
}
void TestBigIntCreate(int n)
{
printf("TestBigIntCreate:%d\n", n);
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
BigInt a = i;
BigInt b = i + 1;
BigInt c = i + 2;
BigInt d = i + 3;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
void TestRCBigIntCreate(int n)
{
printf("TestRCBigIntCreate:%d\n", n);
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
RCBigInt a = i;
RCBigInt b = i + 1;
RCBigInt c = i + 2;
RCBigInt d = i + 3;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
void TestBigIntAssign(int n)
{
printf("TestBigIntAssign:%d\n", n);
BigInt a, b, c, d;
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
a = b = c = d;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
void TestRCBigIntAssign(int n)
{
printf("TestRCBigIntAssign:%d\n", n);
RCBigInt a, b, c, d;
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
a = b = c = d;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
int main()
{
const int NUM = 1000000;
TestBigIntCreate(NUM);
TestRCBigIntCreate(NUM);
TestBigIntAssign(NUM);
TestRCBigIntAssign(NUM);
return 0;
}
运行结果:
最后给出的是多线程版本的代码,在Windows下可以用临界区或者互斥体实现。互斥体实现的版本比较慢,但是临界区的版本为什么在gcc的release版本中运行出现内存错误了,而debug版本中没有问题,在vc6下运行也没有问题。
临界区版本代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <windows.h>
using namespace std;
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;
}
private:
int refCount;
bool shareable;
};
class BigInt
{
friend BigInt operator+(const BigInt&, const BigInt&);
public:
BigInt(const char*);
BigInt(unsigned u = 0);
BigInt(const BigInt&);
BigInt& operator=(const BigInt&);
BigInt& operator+=(const BigInt&);
~BigInt()
{
delete [] digits;
}
char* getDigits() const
{
return digits;
}
unsigned getNdigits() const
{
return ndigits;
}
private:
char* digits;
unsigned ndigits;
unsigned size;
BigInt(const BigInt&, const BigInt&);
char fetch(unsigned i) const
{
return i < ndigits ? digits[i] : 0;
}
};
BigInt::BigInt(const char* s)
{
if (s[0] == '\0')
{
s = "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; ++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)
{
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;
d = digits;
}
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(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 BigInt operator+(const BigInt& left, const BigInt& right)
{
return BigInt(left, right);
}
BigInt& BigInt::operator=(const BigInt& rhs)
{
if (this == &rhs) return *this;
ndigits = rhs.ndigits;
if (ndigits > size)
{
delete [] this;
digits = new char[size = ndigits];
}
for (unsigned i = 0; i < ndigits; ++i)
{
digits[i] = rhs.digits[i];
}
return *this;
}
ostream& operator<<(ostream& os, BigInt& bi)
{
char c;
const char* d = bi.getDigits();
for (int i = bi.getNdigits() - 1; i >= 0; --i)
{
c = d[i] + '0';
os << c;
}
os << endl;
return os;
}
class CriticalSectionLock
{
public:
CriticalSectionLock()
{
InitializeCriticalSection(&csMyCriticalSection);
}
~CriticalSectionLock()
{
DeleteCriticalSection(&csMyCriticalSection);
}
void lock()
{
EnterCriticalSection(&csMyCriticalSection);
}
void unlock()
{
LeaveCriticalSection(&csMyCriticalSection);
}
private:
CRITICAL_SECTION csMyCriticalSection;
};
template <typename T, typename LOCK> class RCIPtr
{
public:
RCIPtr(T* realPtr = NULL) : counter(new CountHolder)
{
counter->pointee = realPtr;
Init();
}
RCIPtr(const RCIPtr& rhs) : counter(rhs.counter)
{
if (rhs.counter) rhs.counter->key.lock();
Init();
if (rhs.counter) rhs.counter->key.unlock();
}
~RCIPtr()
{
if (counter)
{
counter->key.lock();
counter->removeReference();
counter->key.unlock();
}
}
T* operator->() const { return counter->pointee; }
T& operator*() const { return *(counter->pointee); }
RCIPtr& operator=(const RCIPtr& rhs);
private:
struct CountHolder : public RCObject
{
~CountHolder() { delete pointee; }
T* pointee;
LOCK key;
};
CountHolder* counter;
void Init();
};
template <typename T, typename LOCK> void RCIPtr<T, LOCK>::Init()
{
if (counter == 0) return;
if (counter->isShareable() == false)
{
counter = new CountHolder;
counter->pointee = new T(*counter->pointee);
}
counter->addReference();
}
template <typename T, typename LOCK>
RCIPtr<T, LOCK>& RCIPtr<T, LOCK>::operator=(const RCIPtr& rhs)
{
if (counter != rhs.counter)
{
if (counter)
{
counter->key.lock();
counter->removeReference();
counter->key.unlock();
}
counter = rhs.counter;
if (rhs.counter) rhs.counter->key.lock();
Init();
if (rhs.counter) rhs.counter->key.unlock();
}
return *this;
}
class RCBigInt
{
friend RCBigInt operator+(const RCBigInt&, const RCBigInt&);
public:
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:
RCIPtr<BigInt, CriticalSectionLock> value;
};
inline RCBigInt operator+(const RCBigInt& left, const RCBigInt& right)
{
return RCBigInt(*(left.value) + *(right.value));
}
void TestBigIntCreate(int n)
{
printf("TestBigIntCreate:%d\n", n);
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
BigInt a = i;
BigInt b = i + 1;
BigInt c = i + 2;
BigInt d = i + 3;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
void TestRCBigIntCreate(int n)
{
printf("TestRCBigIntCreate:%d\n", n);
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
RCBigInt a = i;
RCBigInt b = i + 1;
RCBigInt c = i + 2;
RCBigInt d = i + 3;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
void TestBigIntAssign(int n)
{
printf("TestBigIntAssign:%d\n", n);
BigInt a, b, c, d;
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
a = b = c = d;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
void TestRCBigIntAssign(int n)
{
printf("TestRCBigIntAssign:%d\n", n);
RCBigInt a, b, c, d;
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
a = b = c = d;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
int main()
{
const int NUM = 1000000;
TestBigIntCreate(NUM);
TestRCBigIntCreate(NUM);
TestBigIntAssign(NUM);
TestRCBigIntAssign(NUM);
return 0;
}
在vc6下的运行结果,
从结果中可以看出RCIBigInt的赋值操作情况在性能上已经没有多少优势了,在vc6下反而更慢,这主要是因为线程同步操作的原因。
互斥体版本代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <windows.h>
using namespace std;
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;
}
private:
int refCount;
bool shareable;
};
class BigInt
{
friend BigInt operator+(const BigInt&, const BigInt&);
public:
BigInt(const char*);
BigInt(unsigned u = 0);
BigInt(const BigInt&);
BigInt& operator=(const BigInt&);
BigInt& operator+=(const BigInt&);
~BigInt()
{
delete [] digits;
}
char* getDigits() const
{
return digits;
}
unsigned getNdigits() const
{
return ndigits;
}
private:
char* digits;
unsigned ndigits;
unsigned size;
BigInt(const BigInt&, const BigInt&);
char fetch(unsigned i) const
{
return i < ndigits ? digits[i] : 0;
}
};
BigInt::BigInt(const char* s)
{
if (s[0] == '\0')
{
s = "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; ++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)
{
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;
d = digits;
}
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(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 BigInt operator+(const BigInt& left, const BigInt& right)
{
return BigInt(left, right);
}
BigInt& BigInt::operator=(const BigInt& rhs)
{
if (this == &rhs) return *this;
ndigits = rhs.ndigits;
if (ndigits > size)
{
delete [] this;
digits = new char[size = ndigits];
}
for (unsigned i = 0; i < ndigits; ++i)
{
digits[i] = rhs.digits[i];
}
return *this;
}
ostream& operator<<(ostream& os, BigInt& bi)
{
char c;
const char* d = bi.getDigits();
for (int i = bi.getNdigits() - 1; i >= 0; --i)
{
c = d[i] + '0';
os << c;
}
os << endl;
return os;
}
class MutexLock
{
public:
MutexLock()
{
hMutex = CreateMutex(NULL, FALSE, NULL);
}
~MutexLock()
{
CloseHandle(hMutex);
}
void lock()
{
WaitForSingleObject(hMutex, INFINITE);
}
void unlock()
{
ReleaseMutex(hMutex);
}
private:
HANDLE hMutex;
};
template <typename T, typename LOCK> class RCIPtr
{
public:
RCIPtr(T* realPtr = NULL) : counter(new CountHolder)
{
counter->pointee = realPtr;
Init();
}
RCIPtr(const RCIPtr& rhs) : counter(rhs.counter)
{
if (rhs.counter) rhs.counter->key.lock();
Init();
if (rhs.counter) rhs.counter->key.unlock();
}
~RCIPtr()
{
if (counter)
{
counter->key.lock();
counter->removeReference();
counter->key.unlock();
}
}
T* operator->() const { return counter->pointee; }
T& operator*() const { return *(counter->pointee); }
RCIPtr& operator=(const RCIPtr& rhs);
private:
struct CountHolder : public RCObject
{
~CountHolder() { delete pointee; }
T* pointee;
LOCK key;
};
CountHolder* counter;
void Init();
};
template <typename T, typename LOCK> void RCIPtr<T, LOCK>::Init()
{
if (counter == 0) return;
if (counter->isShareable() == false)
{
counter = new CountHolder;
counter->pointee = new T(*counter->pointee);
}
counter->addReference();
}
template <typename T, typename LOCK>
RCIPtr<T, LOCK>& RCIPtr<T, LOCK>::operator=(const RCIPtr& rhs)
{
if (counter != rhs.counter)
{
if (counter)
{
counter->key.lock();
counter->removeReference();
counter->key.unlock();
}
counter = rhs.counter;
if (rhs.counter) rhs.counter->key.lock();
Init();
if (rhs.counter) rhs.counter->key.unlock();
}
return *this;
}
class RCBigInt
{
friend RCBigInt operator+(const RCBigInt&, const RCBigInt&);
public:
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:
RCIPtr<BigInt, MutexLock> value;
};
inline RCBigInt operator+(const RCBigInt& left, const RCBigInt& right)
{
return RCBigInt(*(left.value) + *(right.value));
}
void TestBigIntCreate(int n)
{
printf("TestBigIntCreate:%d\n", n);
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
BigInt a = i;
BigInt b = i + 1;
BigInt c = i + 2;
BigInt d = i + 3;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
void TestRCBigIntCreate(int n)
{
printf("TestRCBigIntCreate:%d\n", n);
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
RCBigInt a = i;
RCBigInt b = i + 1;
RCBigInt c = i + 2;
RCBigInt d = i + 3;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
void TestBigIntAssign(int n)
{
printf("TestBigIntAssign:%d\n", n);
BigInt a, b, c, d;
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
a = b = c = d;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
void TestRCBigIntAssign(int n)
{
printf("TestRCBigIntAssign:%d\n", n);
RCBigInt a, b, c, d;
clock_t beg = clock();
for (int i = 0; i < n; ++i)
{
a = b = c = d;
}
clock_t end = clock();
printf("use %f second(s).\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
int main()
{
const int NUM = 1000000;
TestBigIntCreate(NUM);
TestRCBigIntCreate(NUM);
TestBigIntAssign(NUM);
TestRCBigIntAssign(NUM);
return 0;
}
从图里面还是能看到,在Windows下用互斥体同步确实比较慢。
http://www.xpc-yx.com/2012/12/11/%e5%bc%95%e7%94%a8%e8%ae%a1%e6%95%b0/