C++实现对象和接口的弱引用

来源:互联网 发布:淘宝 百科 编辑:程序博客网 时间:2024/06/07 06:37

  弱引用是相对于强引用而言,它引用一个对象但是又不控制对象的生存时期,然后在使用时需要先检查引用的对象是否还存在。而强引用,一般是基于引用计数,引用计数明确的控制了对象的生存时期。如果按控制关系排一个顺序,就是:强引用控制对象生存时期,对象生存时期控制弱引用是否有效,弱引用则什么也没控制,它本身就是一个对象(例如C#里的System.WeakReference),高级一点可以是个模板。

  弱引用貌似是各种高级语言中的神器,不过只要想费一点功夫,C++语言也可以实现,本文实现的版本是一个模板。弱引用实现的关键在于,当对象被删除时,需要及时的改变弱引用的状态,这需要引用的对象本身实现这些功能。因此为了实现弱引用,必须规定一个支持弱引用的基类,然后继承它的类都可以支持弱引用。这个类设计出来大概是这个样子:

h文件代码

struct WeakRefObj{private:    void* _internal;protected:    WeakRefObj();public:    ~WeakRefObj();    void add_weak_ref(WeakRefObj** ref_ptr);    void release_weak_ref(WeakRefObj** ref_ptr, const bool clear_ref_ptr = false);};

  既然是基类,总是希望尽可能的简洁,尤其希望极少甚至没有成员变量声明在头文件里。不过研究了很久,总是不能避免添加成员变量,为了不让头文件暴漏太多内容,只声明了一个void* _internal,实际内容在实现代码中才能取得。

  弱引用的关键功能通过 add_weak_refrelease_weak_ref 实现,add_weak_ref 是用来记下一个WeakRefObj* 变量的地址,通过记录变量地址 WeakRefObj**,这个变量就变成形式上的弱引用了。release_weak_ref 是把一个WeakRefObj* 变量的地址从记录中删除,使它还原为普通的变量。还有一个关键的函数,析构函数,在析构函数里要对已经记录的变量进行清零,这样当对象被删除后,所有被当做弱引用的变量都变成空值。在高级语言中,这个操作可能是垃圾回收器在某个时刻延时完成的,但在C++里必须在析构时全部清零。这样,弱引用的所有功能就算实现了。

  不用多说,这里面有一大堆多线程同步问题要解决,不过先不考虑这些,暂时允许代码不是线程安全的。下面的实现过程中,记录的变量地址需要由 WeakRefObj 本身来保存,最简单的就是用std::set<T> 容器,void* _internal 可以指向一个std::set<WeakRefObj**>

cpp文件代码

#include"WeakRefObj.h"#include<set>WeakRefObj::WeakRefObj{    this->_internal = new std::set<WeakRefObj**>();}WeakRefObj::~WeakRefObj{    if(this->_internal != NULL)    {        std::set<WeakRefObj**>* weak_refs = (std::set<WeakRefObj**>*)this->_internal;        for(std::set<WeakRefObj**>::iterator i = weak_refs->begin(), i_end = weak_refs->end(); i != i_end; i++)        {            (*(*i)) = NULL;        }        delete weak_refs;    }}void WeakRefObj::add_weak_ref(WeakRefObj** ref_ptr){    std::set<WeakRefObj**>* weak_refs;    if((*ref_ptr) != NULL)    {        weak_refs = (std::set<WeakRefObj**>*)(*ref_ptr)->_internal;        weak_refs->erase(ref_ptr);    }    weak_refs = (std::set<WeakRefObj**>*)this->_internal;    weak_refs->insert(ref_ptr);    (*ref_ptr) = this;}void WeakRefObj::release_weak_ref(WeakRefObj** ref_ptr, const bool clear_ref_ptr){    std::set<WeakRefObj**>* weak_refs = (std::set<WeakRefObj**>*)this->_internal;    weak_refs->erase(ref_ptr);    if(clear_ref_ptr)    {        (*ref_ptr) = NULL;    }}

  这里实现弱引用的方法和boost还是有区别的,boost中的弱引用是依赖一个强引用,就是需要有一个智能指针,而这里实现的弱引用和强引用无关,只跟变量和引用对象有关系。不过,如果只靠这两个函数管理变量地址来表示弱引用,代码写起来实在是比较晦涩,即使保证了 add_weak_ref 和 release_weak_ref 成对使用,有时也很难分清一个变量是否变成弱引用了。所以,我们应该像高级语言一样,再封装出一个弱引用对象出来。这时模板就派上用场了,可以写一个弱引用模板把 add_weak_ref 和 release_weak_ref 封装起来。用户可以选择是使用模板还是亲自使用变量。

template<typename T> struct TWeakRefPtr{private:    WeakRefObj* m;public:    TWeakRefPtr(): m(0) { };    TWeakRefPtr(const TWeakRefPtr& value): m(0)    {        if(value.m != 0)            value.m->add_weak_ref(&this->m);    };    TWeakRefPtr(T* ptr_t): m(0)    {        if(dynamic_cast<WeakRefObj*>(ptr_t) != 0)            static_cast<WeakRefObj*>(ptr_t)->add_weak_ref(&this->m);    };    ~TWeakRefPtr()    {        if(this->m != 0)            this->m->release_weak_ref(&this->m);    };    operator T*()    {        return dynamic_cast<T*>(this->m);    };    operator const T*() const    {        return dynamic_cast<const T*>(this->m);    };    TWeakRefPtr& operator =(T* ptr_t)    {        if(this->m != 0)            this->m->release_weak_ref(&this->m);        if(dynamic_cast<WeakRefObj*>(ptr_t) != 0)        {            static_cast<WeakRefObj*>(ptr_t)->add_weak_ref(&this->m);        }        else        {            this->m = 0;        }        return (*this);    };    TWeakRefPtr& operator =(const TWeakRefPtr& value)    {        if(this->m != 0)            this->m->release_weak_ref(&this->m);        if(value.m != 0)        {            value.m->add_weak_ref(&this->m);        }        else        {            this->m = 0;        }        return (*this);    };    bool operator ==(const TWeakRefPtr& value) const    {        return (this->m == value.m);    };    bool operator ==(T* ptr_t) const    {        return (this->m == static_cast<WeakRefObj*>(ptr_t));    };    bool operator !=(const TWeakRefPtr& value) const    {        return (this->m != value.m);    };    bool operator !=(T* ptr_t) const    {        return (this->m != static_cast<WeakRefObj*>(ptr_t));    };    bool operator <(const TWeakRefPtr& value) const    {        return (this->m < value.m);    };    T* operator ->() const    {        return static_cast<T*>(this->m);    };};

  模板没法封装,必须在头文件里写完,虽然代码很多,不过关键功能都是靠 add_weak_ref 和 release_weak_ref 实现,这两个函数的实现代码是隐藏在cpp文件里的,也算是封装了。

  如果考虑线程安全,要做的事就多了,最简单的,Windows平台可以用 CRITICAL_SECTION,WeakRefObj对象可以维护一个CRITICAL_SECTION,不仅使管理弱引用变得线程安全,还可以加两个成员函数:

  sync_lock() 调用EnterCriticalSection,

  sync_unlock() 调用LeaveCriticalSection,

  这样顺便让整个对象甚至继承的对象都是线程安全的。

  从系统设计上来看,弱引用使代码逻辑看起来比强引用更和谐。强引用管理对象可靠,但是不能克服循环引用的顽疾,弱引用对此是一个弥补。出现循环引用的根本原因是接口内部实现者之间发生了强引用,而这个强引用并不是使用者亲自增加的,所以使用者没把它当做一次引用。从系统设计上来说,应该是只有接口的使用者有权管理强引用,接口的内部实现者如果需要相互引用,应该全都是弱引用。当使用者通过强引用释放接口时,内部实现者通过检查弱引用是否失效作出正确的处理,就可以避免引用循环造成的悲剧。

  按照这样的想法,接口的实现者最好既支持强引用又支持弱引用,因此这个WeakRefObj可以继续改进,最后成为一个通用的接口基类interface_type。由于包含了一个 void* _internal 成员变量,最终形成的类不算真正意义上的接口,不过 _internal 是私有且无明确类型,继承后也无法访问到,然后可以通过protected关键字隐藏构造函数和析构函数,使接口类公开后既不被能构造也不能被析构,只能通过强引用(引用计数)管理接口的生存时期,同时支持弱引用,这样作为接口还勉强可以接受。其实,通过重载 new 操作符多分配一点空间然后返回偏移的地址,或者像高级语言一样在某个堆空间里额外保存所有实例的引用状态,这个 void* _internal 也是可以消除的,不过由此带来的多线程安全问题和性能下降都很严重,所以就保留现状了。如何去除这个唯一成员变量暂时没思路了。可怜

  最后贴上接口基类的部分代码,实现过程太多就省略cpp文件了,贴出头文件以表明设计思路。强引用,弱引用,聚合接口查询,都支持了,强引用和弱引用都是以模板类型实现,而且各自可以独立使用。测试了一下两种避免声明成员变量的方法,在堆空间做统一管理会效率低下,重载new函数又会限制上层的开发自由,所以最后无奈还是选择声明一个成员变量,不过也懒得起名字了,用一个下划线表示,不希望被注意到,就这样好了。害羞

interface_type.h

#ifndef __INTERFACE_TYPE_H#define __INTERFACE_TYPE_H//接口唯一标识类型。typedef long long TYPEID;const TYPEID TYPE_NULL = 0x0000000000000000;//接口函数返回类型。typedef short RESULT;const RESULT RESULT_OK = 0x0000;const RESULT ERR_UNKNOWN = 0xffff;const RESULT ERR_CONV_TYPE_FAILED = 0x1001;const RESULT ERR_ACCESS_NULL_ADDR = 0x1002;//接口类型基类。struct interface_type{private: void* _;protected:    //构造函数(仅继承类型可调用)。    interface_type();    //析构函数(仅继承类型可调用)。    virtual ~interface_type();    //隐藏此函数以禁止创建实例数组。    void* operator new[](const size_t arr_size) throw(RESULT);    //隐藏此函数以禁止删除实例数组。    void operator delete[](void* arr_addr) throw(RESULT);public:    //使当前线程安全访问接口。    void sync_lock();    //结束当前线程的安全访问。    void sync_unlock();    //增加一次强引用。这将使强引用计数增加。    void add_safe_ref();    //把普通地址变量转换为弱引用变量。转换后的变量成为实例的一个弱引用。    void add_weak_ref(interface_type** ref_ptr);    //减少一次强引用。这将使强引用计数减少,当强引用计数减少至零时,对象就立刻被删除,相关的任何弱引用也将一起失效。    void safe_release();    //把弱引用变量转换为普通地址变量。转换后的变量被还原成普通的地址变量。    void weak_release(interface_type** ref_ptr, const bool clear_ref_ptr = false);    //请求指定的聚合接口。继承接口并重写此函数,以取得其它接口。    virtual RESULT query_type_t(const TYPEID type, interface_type **result)    {        //仅演示取得"interface_type"类型。        if(type == TYPE_NULL)        {            if(result != 0)            {                this->add_safe_ref();                if((*result) != 0)                {                    (*result)->safe_release();                }                (*result) = static_cast<interface_type*>(this);                return RESULT_OK;            }            else            {                return ERR_ACCESS_NULL_ADDR;            }        }        else        {            return ERR_CONV_TYPE_FAILED;        }    };};//接口的强引用类型。template<typename T> struct safe_ref_t{private:    interface_type* m;public:    safe_ref_t(): m(0) { };    safe_ref_t(const safe_ref_t& value): m(value.m)    {        if(this->m != 0)        this->m->add_safe_ref();    };    safe_ref_t(T* ptr_t): m(dynamic_cast<interface_type*>(ptr_t))    {    if(this->m != 0)        this->m->add_safe_ref();    };    ~safe_ref_t()    {        if(this->m != 0)            this->m->safe_release();    };    operator T*()    {        return dynamic_cast<T*>(this->m);    };    operator const T*() const    {        return dynamic_cast<const T*>(this->m);    };    safe_ref_t& operator =(T* ptr_t)    {        if(dynamic_cast<interface_type*>(ptr_t) != 0)            static_cast<interface_type*>(ptr_t)->add_safe_ref();        if(this->m != 0)            this->m->safe_release();        this->m = dynamic_cast<interface_type*>(ptr_t);        return (*this);    };    safe_ref_t& operator =(const safe_ref_t& value)    {        if(value.m != 0)            value.m->add_safe_ref();        if(this->m != 0)            this->m->safe_release();        this->m = value.m;        return (*this);    };    bool operator ==(const safe_ref_t& value) const    {        return (this->m == value.m);    };    bool operator ==(T* ptr_t) const    {        return (this->m == static_cast<interface_type*>(ptr_t));    };    bool operator !=(const safe_ref_t& value) const    {        return (this->m != value.m);    };    bool operator !=(T* ptr_t) const    {        return (this->m != static_cast<interface_type*>(ptr_t));    };    bool operator <(const safe_ref_t& value) const    {        return (this->m < value.m);    };    T* operator ->() const    {        return static_cast<T*>(this->m);    };};//接口的弱引用类型。template<typename T> struct weak_ref_t{private:    interface_type* m;public:    weak_ref_t(): m(0) { };    weak_ref_t(const weak_ref_t& value): m(0)    {        if(value.m != 0)            value.m->add_weak_ref(&this->m);    };    weak_ref_t(T* ptr_t): m(0)    {        if(dynamic_cast<interface_type*>(ptr_t) != 0)        static_cast<interface_type*>(ptr_t)->add_weak_ref(&this->m);    };    ~weak_ref_t()    {        if(this->m != 0)            this->m->weak_release(&this->m);    };    operator T*()    {        return dynamic_cast<T*>(this->m);    };    operator const T*() const    {        return dynamic_cast<const T*>(this->m);    };    weak_ref_t& operator =(T* ptr_t)    {        if(this->m != 0)            this->m->weak_release(&this->m);        if(dynamic_cast<interface_type*>(ptr_t) != 0)        {            static_cast<interface_type*>(ptr_t)->add_weak_ref(&this->m);        }        else        {            this->m = 0;        }        return (*this);    };    weak_ref_t& operator =(const weak_ref_t& value)    {        if(this->m != 0)        this->m->weak_release(&this->m);        if(value.m != 0)        {            value.m->add_weak_ref(&this->m);        }        else        {            this->m = 0;        }        return (*this);    };    bool operator ==(const weak_ref_t& value) const    {        return (this->m == value.m);    };    bool operator ==(T* ptr_t) const    {        return (this->m == static_cast<interface_type*>(ptr_t));    };    bool operator !=(const weak_ref_t& value) const    {        return (this->m != value.m);    };    bool operator !=(T* ptr_t) const    {        return (this->m != static_cast<interface_type*>(ptr_t));    };    bool operator <(const weak_ref_t& value) const    {        return (this->m < value.m);    };    T* operator ->() const    {        return static_cast<T*>(this->m);    };};#endif
原创粉丝点击