引用计数与对象生存期管理

烽驿2009开源实时通信平台 源码获取:svn checkout http://fy2009.googlecode.com/svn/trunk/ fy2009-read-only 

 

对象生存期管理是程序设计的一项重要内容。目前流行的对象生存期管理手段主要是各类垃圾回收(GC)

机制。其优点是使用简单,程序员只需负责对象创建,而不用关心对象销毁,但垃圾回收机制通常和语言

本身绑定,主要用于各类解释或半解释型语言,如Java,C#等,在C++中未见采用。C++中普遍采用的对象

生存期管理基于所谓的引用计数实现。即被管理的堆对象(分配在Heap上)内部维持一个叫做引用计数的

成员变量,每将该对象指针赋给一个变量,就对引用计数加一,每有一个这样的变量走出作用域,将相应

的引用计数减一,当引用计数减到零时,表示不再有任何变量指向该对象,自动销毁该对象。为规范引用

计数管理,定义统一接口如下:
class ref_cnt_it : public lookup_it
{
public:
        virtual void add_reference()=0;
        virtual void release_reference()=0;
        virtual uint32 get_ref_cnt() const throw()=0; //for tracibility
};
所有支持引用计数的Class必需实现该接口,另外,为阻止程序员误将该类型的对象分配在栈(Stack)上,最好

将其构造函数申明成protected。此外,在多线程环境下,还需要考虑引用计数的线程安全性。为简化接口

实现,本项目为上述接口提供了缺省实现:
class ref_cnt_impl_t : public ref_cnt_it
{
public:
       virtual ~ref_cnt_impl_t(){}

        //set_lock is called with a non-null para will enable thread-safe
        void set_lock(critical_section_t *cs) throw();

        bool is_thread_safe() const throw() { return _p_cs!=0; }

        //lookup_i
        void *lookup(uint32 iid) throw();

        //ref_cnt_i
        void add_reference();
        void release_reference();
        inline uint32 get_ref_cnt() const throw(){ return _ref_cnt; }
protected:
        //disable instantiate it directly
        ref_cnt_impl_t() throw();
        ref_cnt_impl_t(critical_section_t *cs) throw();

protected:
        uint32 _ref_cnt;
        critical_section_t *_p_cs;//set it to nonull,it will be thread-safe
};
用户Class通过实现继承该类支持引用计数,该实现提供了引用计数的线程安全性选择。加/减引用计数

通常是相当频繁的操作,效率至关重要,而加/解锁操作通常有着较大开销,因此,为非必要, 尽

量采用非线程安全型引用计数。通过认真规划系统线程模型(这同样是一个生要专题,我们后面会讲到)

,通常可以大大降低对对象线程安全性的要求。
如前所述,理论上,引用计数机制要求程序员小心跟踪每个持有对象指针的变量,在它们走出作用域时,手

工调用上述release_reference(),不能有任何一次遗漏,否则将引起在C/C++世界臭名昭著的内存泄漏

(Memory Leak)。实践证明,这通常是一件让程序员白天“抓狂”,晚上做恶梦的工作。所幸,我们有一

个聪明的办法来大大简化这个不幸的工作:智能指针(Smart Pointer),它是一个指针封装(Wrapper)

,基本思路是,Smart Pointer总被申明成栈变量(其自身的生存期不需要管理),裸对象指针总被封在

Smart Pointer实例中,并在封入时由Smart Pointer自动调用被封对象的add_reference, 当Smart

Pointer所在的栈“卷出”时,自动调用被封对象的release_reference。另外,在Smart Pointer相互间赋

值,Copy构造时都需要做相应的add_reference/release_reference工作。这些都是自动的,也就是说,有

了Smart Pointer,程序员永远不需要自己调用add_reference/release_reference,唯一需要做的就是总

是通过Smart Pointer引用对象,永远不要持有一个裸对象指针。当然,在某些情况下,Smart Pointer可

能会调用add_reference/release_reference多于必要的次数。通常这不是什么大问题,如果你确实觉得

这影响了你的系统性能(比如用STL容器管理一个引用计数Thread-Safe的对象时),你仍然可以在必要的局部将

裸对象指针从Smart Pointer中解偶,并小心谨慎地手工处理引用计数操作。再说一句,除非测试证明实样做收益显著,否则,这样做通常是不明智的。
Smart Pointer实际上是一个类模板:
template < typename T> class smart_pointer_tt
{
...
}
实际使用时,将支持引用计数的用户Class作为T传入模板,将其“特殊化”(Specialize)成特定的Smart

Pointer类型。

另外,为支持前面博文提到的基于lookup_it接口的动态类型发现机制,定义另一Smart Pointer模板如下


template < typename T> class smart_pointer_lu_tt
{
...
}
特殊化该模板所指定的T可以是任何一个直接或间接继承自lookup_it的接口类型,然后通过lookup机

制,即可实现同一Class所实现的多个接口类型之间的Smart Pointer转换。

 

Smart Pointer类型转换宏:
#define SP_CAST(dest_type, src_type, src_sp) (smart_pointer_tt< dest_type >((dest_type*)

(src_type*)src_sp, true))
该宏用于非lookup机制的两种Smart Pointer类型之间的转换。其前提是,将源Smart Pointer对应的裸类

型强转成目标Smart Pointer对应的裸类型是有定义的。
#define SP_LU_CAST(dest_type, dest_type_id, src_sp) (smart_pointer_lu_tt< dest_type >(/
                   (dest_type*)src_sp->lookup(dest_type_id),true))
该宏用于同一Class所实现的多种支持lookup机制的接口类型所对应Smart Pointer之间的转换。

另外,将一个不支持引用计数的堆指针(如new出来的Buffer指针)封装(Wrapp)成支持引用计数的对象

是可能的。下面的模板即完成该操作:
template < typename T> class ref_cnt_adaptor_tt : public ref_cnt_impl_t
{
...
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值