C++ 簡易string類實現(五)-進一步抽象

前四篇所敘述的每一件事情,都必須動用到我們感興趣的那個class的源代碼.但如果我們想要將reference counting施行於程序庫中一個名爲Widget的class呢?程序庫的行爲不是我們可以更改的,所以沒辦法讓Widget繼承自RCObject,也就無法對Widget使用smart RCPtrs.

但只要稍微修改設計,我們就可以爲任何類型加上reference counting能力.

首先,讓我們考慮,如果令Widget繼承自RCObject,我們的設計看起來將如何.這種情況下,我們必須增加一個RCWidget class給clients使用,但每件事情都極類似先前的String/StringValue例子:RCWidget扮演String角色,Widget扮演StringValue的角色.整個設計看起來去如下:
這裏寫圖片描述
現在我們可以將”計算機科學領域中大部分問題得以解決”的原理施展出來.我們可以加上一層間接性.是的,我們增加一個新的CountHolder class,用以持有引用次數,並令CountHolder繼承自RCObject.我們也令CountHolder內含一個指針,指向一個Widget.然後將smart RCPtr template以同樣聰明的RCIPtr template取代,後者知道CountHolder class 的存在.RCIPtr的”I”意指”indirect”(間接).修改後的設計如下:
這裏寫圖片描述
就像”StringValue只是實現細節,不需要讓String的用戶知道”一樣,CountHolder也是實現細節,不需要讓RCWidget的用戶知道.事實上,它是RCIPtr的實現細節,所以我們把它嵌套放進RCIPtr class的內部.RCIPtr的聲明如下:

template<typename T>
class RCIPtr
{
public:
    RCIPtr(T* realPtr = nullptr);

    RCIPtr(const RCIPtr& rhs_);

    RCIPtr& operator=(const RCIPtr& rhs_);

    ~RCIPtr();

public:
    const T* operator->() const;

    T* operator->();

    const T& operator*() const;

    T& operator*();

private:
    void init();

    void makeCopy();

private:
    struct CountHolder : public RCObject
    {
        T* ptr;

        ~CountHolder()
        {
            if (ptr != nullptr)
            {
                delete ptr;
                ptr = nullptr;
            }
        }
    };

    CountHolder* _counter;
};

RCIPtr和RCPtr之間存在兩個差異.第一,”RCPtr對象”之間指向實值,而”RCIPtr對象”通過中介層”CountHolder”對象指向實值;第二,RCIPtr將operator->和operator*重載了,如此一來,只要有non-const access發生於被指物上,copy-on-write(寫時進行復制)就會自動執行.

RCIPtr定義如下:

template<typename T>
void RCIPtr<T>::init()
{
    if (_counter->isShareable() == false)
    {
        auto oldptr = _counter->ptr;
        _counter = new CountHolder();
        _counter->ptr = new T(*oldptr);
    }
    _counter->addReference();
}

template<typename T>
RCIPtr<T>::RCIPtr(T* realPtr /* = nullptr */)
    : _counter(new CountHolder())
{
    _counter->ptr = realPtr;
    init();
}

template<typename T>
RCIPtr<T>::RCIPtr(const RCIPtr& rhs_)
    : _counter(rhs_._counter)
{
    init();
}

template<typename T>
RCIPtr<T>& RCIPtr<T>::operator=(const RCIPtr& rhs_)
{
    if (_counter ! = rhs_._counter)
    {
        _counter->removeReference();
        _counter = rhs_._counter;
        init();
    }
    return *this;
}

template<typename T>
RCIPtr<T>::~RCIPtr()
{
    _counter->removeReference();
}

template<typename T>
const T* RCIPtr<T>::operator->() const
{
    return _counter->ptr;
}

template<typename T>
T* RCIPtr<T>::operator->()
{
    makeCopy();
    return _counter->ptr;
}

template<typename T>
const T& RCIPtr<T>::operator*() const
{
    return *(_counter->ptr);
}

template<typename T>
T& RCIPtr<T>::operator*()
{
    makeCopy();
    return *(_counter->ptr);
}

template<typename T>
void RCIPtr<T>::makeCopy()
{
    if (_counter->isShared())
    {
        auto oldptr = _counter->ptr;
        _counter->removeReference();
        _counter = new CountHolder();
        _counter->ptr = new T(*oldptr);
        _counter->addReference();
    }
}

有了RCIPtr,RCWidget的實現就很容易了,因爲RCWidget的每一個函數都只是通過底層的RCIPtr轉調對應的Widget函數.示例如下:

class Widget
{
public:
    void doThis()
    {
        std::cout << "doThis" << std::endl;
    }
};

class RCWidget
{
public:
    void doThis()
    {
        _value->doThis();
    }

private:
    RCIPtr<Widget> _value;
};

對於String類,我們只需要將C++ 簡易string類實現(一)參考上述Widget和RCWidget的例子,生成一個對應的RCString就OK了;

小結:通過不斷的抽象,最終將引用計數類和用戶自定義類完全解耦,而且引用計數類還可以重用於其它用戶自定義類,簡直 完美!!!

完整代碼如下:

class RCObject
{
public:
    RCObject();

    RCObject(const RCObject& rhs_);

    //使RCObject成爲抽象基類,但該純虛函數需要提供
    //定義,不然會使被繼承的類無法在棧上創建(原因可
    //查閱如何僅在堆上或棧上分配內存)
    virtual ~RCObject() = 0;       

public:
    void addReference();

    void removeReference();

    void  markUnshareable();

    bool isShareable() const;

    bool isShared() const;

private:
    RCObject& operator=(const RCObject&) = delete;

private:
    int refCount;
    bool shareable;
};


template<typename T>
class RCIPtr
{
public:
    RCIPtr(T* realPtr = nullptr);

    RCIPtr(const RCIPtr& rhs_);

    RCIPtr& operator=(const RCIPtr& rhs_);

    ~RCIPtr();

public:
    const T* operator->() const;

    T* operator->();

    const T& operator*() const;

    T& operator*();

private:
    void init();

    void makeCopy();

private:
    struct CountHolder : public RCObject
    {
        T* ptr;

        ~CountHolder()
        {
            if (ptr != nullptr)
            {
                delete ptr;
                ptr = nullptr;
            }
        }
    };

    CountHolder* _counter;
};
RCObject::RCObject()
    :refCount(0), shareable(true)   //refCount初始化爲0,其值完全有RCPtr控制
{
}

RCObject::RCObject(const RCObject&)
//調用無參構造函數,注意:該調用僅能在
//初始化成員列表裏,如果在函數實現內調用,
//那麼僅僅是在棧上生成新的對象,而不是完成
//該對象的成員初始化
    :RCObject()
{
    std::cout << "RCObject" << std::endl;
}

RCObject::~RCObject()
{
    //std::cout << "~RCObject" << std::endl;
}

void RCObject::addReference()
{
    ++refCount;
}

void RCObject::removeReference()
{
    if (--refCount == 0)
    {
        delete this;
    }
}

void RCObject::markUnshareable()
{
    shareable = false;
}

bool RCObject::isShareable() const
{
    return shareable;
}

bool RCObject::isShared() const
{
    return refCount > 1;
}

template<typename T>
void RCIPtr<T>::init()
{
    if (_counter->isShareable() == false)
    {
        auto oldptr = _counter->ptr;
        _counter = new CountHolder();
        _counter->ptr = new T(*oldptr);
    }
    _counter->addReference();
}

template<typename T>
RCIPtr<T>::RCIPtr(T* realPtr /* = nullptr */)
    : _counter(new CountHolder())
{
    _counter->ptr = realPtr;
    init();
}

template<typename T>
RCIPtr<T>::RCIPtr(const RCIPtr& rhs_)
    : _counter(rhs_._counter)
{
    init();
}

template<typename T>
RCIPtr<T>& RCIPtr<T>::operator=(const RCIPtr& rhs_)
{
    if (_counter ! = rhs_._counter)
    {
        _counter->removeReference();
        _counter = rhs_._counter;
        init();
    }
    return *this;
}

template<typename T>
RCIPtr<T>::~RCIPtr()
{
    _counter->removeReference();
}

template<typename T>
const T* RCIPtr<T>::operator->() const
{
    return _counter->ptr;
}

template<typename T>
T* RCIPtr<T>::operator->()
{
    makeCopy();
    return _counter->ptr;
}

template<typename T>
const T& RCIPtr<T>::operator*() const
{
    return *(_counter->ptr);
}

template<typename T>
T& RCIPtr<T>::operator*()
{
    makeCopy();
    return *(_counter->ptr);
}

template<typename T>
void RCIPtr<T>::makeCopy()
{
    if (_counter->isShared())
    {
        auto oldptr = _counter->ptr;
        _counter->removeReference();
        _counter = new CountHolder();
        _counter->ptr = new T(*oldptr);
        _counter->addReference();
    }
}
發佈了23 篇原創文章 · 獲贊 10 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章