引用计数

来源:互联网 发布:ips 知乎 编辑:程序博客网 时间:2024/05/20 03:43

引用计数

  引用计数说得直接点就是不同的对象内部共享同样的内容(内存),同时对象能够自己跟踪自己被引用多少次,能够在没有被继续引用的时候删除自己,保证了没有内存泄漏的出现。看起来貌似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;}

在codeblocks配gcc的环境下的运行结果,

  从图里面还是能看到,在Windows下用互斥体同步确实比较慢。

http://www.xpc-yx.com/2012/12/11/%e5%bc%95%e7%94%a8%e8%ae%a1%e6%95%b0/

0 0
原创粉丝点击