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();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值