修破门 的个人资料修破门之界照片日志列表更多 工具 帮助

日志


2007/10/28

用C++实现带引用计数并且线程安全的智能指针

    仔细想一下要做一个和boost里的share_ptr类似的带引用计数的智能指针也不是太难,今天下午花了点时间写了一个,支持多线程。

namespace XPtr {

     //引用计数模板对象,L 表示所使用的同步对象类型,用作引用计数增减时做同步操作

    template<typename L>

    class RefCounter {

    private:

        int counter;

        L _lock;

       //同步对象操作辅助类,构造函数中加锁,析构函数中解锁

        class LockHelper {

        private:

            L _l;

        public:

            LockHelper(L &l) {  _l = l;  _l.lock(); }

            ~LockHelper() { _l.unlock(); }

        };

 

    public:

        RefCounter():counter(0) {    }

        //整形转换操作符

        operator int() {   return counter;   }

        //

        int operator++() {

            LockHelper l(_lock);

            return ++counter;

        }

        //

        int operator--() {

            LockHelper l(_lock);

            return --counter;

        }

    };

 

    //单线程时的同步对象,全部为空,不做线程同步

    struct SingleThread {

        void lock() {};

        void unlock() {};

    };

     //主角登场,智能指针模板, T 为指针指向内容,ThreadLock为线程同步策略类,默认为单线程

   

template<typename T, typename ThreadLock = SingleThread> class xptr{

    private:

        T * m_ptr;

        //引用计数类的指针,指向同一个指针的智能指针要共同维护一个引用计数类实例 

        RefCounter<ThreadLock> *m_pCounter;

 

    public:

       //智能指针可以不初始化,待以后赋值

        xptr():m_ptr(0),m_pCounter(0)         {}

 

        //用另一个typename P而不直接用T,这样可以支持用子类的指针类初始化父类智能指针

        //使用explicit关键字,表示禁止隐式类型转换,防止无意识的情况下把已有的原生指针转成智能指针

        template<typename P>

        explicit xptr(P *p)  {  create( new RefCounter<ThreadLock>(), p);    }

        //拷贝构造函数,若需要支持用子类的智能指针初始化,则需要另外申明一个模板拷贝构造函数,增加一个typename P,类似前面的构造函数

        //但由于需要改变引用计数,所以需要智能指针开放接口以取得引用计数对象和原始指针对象,这样会不太雅观,所以这里有个tradeoff  (见肥浩的留言)

        xptr(const xptr<T> &p) {   create(p.m_pCounter,p.m_ptr);    }

        //赋值操作,同上

        const xptr<T>& operator= (const xptr<T> &p) {

            if(&p != this) {

                destory();

                create(p.m_pCounter, p.m_ptr);

            }

            return *this ;

        }

        //析构函数,调用destory()辅助函数,用以减少引用计数,并适时销毁原始指针对象和引用计数对象

        ~xptr() { destory();}

        T* operator->() const{ return m_ptr;}

 

        //布尔值转换操作符,判断是否为空

        operator bool() {   return m_ptr!=0 ;   }

    private:

        //辅助函数,用以增加引用计数,取得原始指针对象和引用计数对象

        template<typename P>

        void create(RefCounter<ThreadLock> * pf , P* pp) {

            m_pCounter = pf;

            if(m_pCounter!=0)

                ++*m_pCounter;

            m_ptr = pp;

        }

        //辅助函数,用以减少引用计数,为零时销毁原始指针对象和引用计数对象

        void destory() {

           //在多线程环境下这里看似会有同步问题,但是那种情况是不会发生的,所以这样是安全的

            if(m_pCounter!=0 && --*m_pCounter==0) {

                delete m_pCounter;

                delete m_ptr;

            }

        }

    };

}

要用在多线程环境中的话需要根据平台实现一个同步类,内部有一个mutex,支持lock, unlock操作,使用时将此同步类作为智能指针的第二个模板参数即可。

2007/10/13

站在巨人的脚后跟上

    最近发生了很多事情,很久没有心思更新blog了。有句话说的好:“出来混迟早要还的”。人要为自己犯的错误或失误付出代价,不管这代价是否公平合理。世界上本来也就没有什么公平可言,付出不一定就能有收获,努力不一定就能成功,坏人不一定会遭到惩罚,好人不一定会有好报。这个道理我很久以前就明白了,这一次再次证实。或许人们对公平的定义不同,你认为不公平的事别人会认为很公平,很难说得清的。就当成是生活中的又一个小坎坷吧,也见多了。特别欣慰的是有朋友看到我MSN签名异常来询问安慰,让我感觉好多了。
       
    言归正传,现在说说长期的困惑,转眼间在新公司又呆了一年了,回顾这一年来,觉得很空虚,不知道自己到底做了些什么有意义的东西,技术上往好了说是几乎没有什么长进,曾经引以为豪的C++现在也是一塌糊涂,毕竟一年没用了!现在用的Java虽说用了一年,可是实际编码时间很少,也就是半瓶子醋水平,和不会没有什么太大的区别,更不用说和自己的C++相比了。不客气地说,整个team这一年来做的东西充其量只相当于三流小公司三个月做出的一个prototype,看上去更像一个玩具(?)而不是什么像样的产品,我实在想不出来里面究竟有些什么技术含量。直到前不久,形势还在瞬息万变,今天说这么做,明天说那么做,今天说做这个,明天说做那个,到底有谱没谱?把所有可能的平台和所有语言都用一用,J2ME, WM, Symbian, C++, C#, Java...,好吧这个只是顺便提提,如果只是没谱的话也还好说,毕竟不是天天没谱。
    当不了巨人的左膀右臂,也站不到巨人的肩膀上,我们只能站在巨人的脚后跟上(怎么站?不好站吧?所以才瞬息万变经常没谱被人牵着鼻子走啊),在自己的三分地上闭门造车,精通木工活的人被派去打铁,精通铁匠活的被派去做木工,拼凑一些不知所谓的玩意,忙着加班却不知道自己在做些什么,也不知道现在做的东西对自己以后的发展有什么帮助。这难道真的是我曾经梦想中的工作吗?还是我太不知足了?
    为了混口饭吃,又能有什么办法呢?