引用计数

引用计数

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值