修破门's profile修破门之界PhotosBlogListsMore Tools Help

Blog


    10/28/2007

    用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操作,使用时将此同步类作为智能指针的第二个模板参数即可。

    5/28/2007

    用C++ templates 实现Lambda(下)

        接上文,_2 _3 的实现。 没想到自己居然这么勤快

    ////////////////////////////////////////////////
    // lambda templates
    namespace XLambda { 
            template <typename T> 
            class CXLambdaLiteral 
            { 
            public: 
                    CXLambdaLiteral(const T &t): m_data(t) {} 
                    template <typename V> 
                    inline V operator() (const V &x) const {return m_data;} 
                    template <typename V> 
                    inline V operator() (const V &x,const V &y) const {return m_data;} 
                    template <typename V> 
                    inline V operator() (const V &x,const V &y,const V &z) const {return m_data;} 
            private: 
                    T m_data; 
            }; 

            class CXLambdaIdentity 
            { 
            public: 
                    template <typename V> 
                    inline V operator() (const V &x) const {return x;} 
                    template <typename V> 
                    inline V operator() (const V &x,const V &y) const {return x;} 
                    template <typename V> 
                    inline V operator() (const V &x,const V &y,const V &z) const {return x;} 
            };  

            class CXLambdaIdentity_2 
            { 
            public: 
                    template <typename V> 
                    inline V operator() (const V &x,const V &y) const {return y;} 
                    template <typename V> 
                    inline V operator() (const V &x,const V &y, const V &z) const {return y;} 
            };  

            class CXLambdaIdentity_3 
            { 
            public: 
                    template <typename V> 
                    inline V operator() (const V &x,const V &y,const V &z) const {return z;} 
            };  

            template <class A,class B,class Op> 
            class CXLambdaBinOp 
            { 
            public: 
                    CXLambdaBinOp(const A &a,const B &b):m_a(a),m_b(b) {} 
                    template <class V> 
                    inline V operator() (const V &x) const 
                    {return Op::apply(m_a(x),m_b(x));} 
                    template <class V> 
                    inline V operator() (const V &x,const V &y) const 
                    {return Op::apply(m_a(x,y),m_b(x,y));} 
                    template <class V> 
                    inline V operator() (const V &x,const V &y,const V &z) const 
                    {return Op::apply(m_a(x,y,z),m_b(x,y,z));} 
            private: 
                    A m_a; 
                    B m_b; 
            };         

            template <class T> 
            class CXLambda 
            { 
            public: 
                    CXLambda(const T &t):m_t(t) {} 
                    CXLambda() {}; 
                    template<class V> 
                    inline V operator()(const V &x) const 
                    {return m_t(x);} 
                    template<class V> 
                    inline V operator()(const V &x, const V &y) const
                    {return m_t(x,y);} 
                    template<class V> 
                    inline V operator()(const V &x, const V &y, const V &z) const 
                    {return m_t(x,y,z);} 
            private: 
                    T m_t; 
            };

            ///////////////////////////////////////////////////////////////////////////////// 
            // 用宏实现重复的运算符重载工作, 宏定义略,参见上篇 

            OP_BIN(Add, +) 
            OP_BIN(Sub, -) 
            OP_BIN(Multiply, *) 
            OP_BIN(Divid, /) 

            ///////////////////////////////////////////////////////////////////////////////// 
            //为方便使用而定义的宏
    #define _1 CXLambda<CXLambdaIdentity>()
    #define _2 CXLambda<CXLambdaIdentity_2>()
    #define _3 CXLambda<CXLambdaIdentity_3>()

    }

          ///////////////////////////////////////////////////////////////////////////
          // test, 一个三元参数的函数对象(一个匿名的functor)的诞生和计算
          printf(
    " %d ",(_1 + _2*_2  + _3*_3*_3+ 1 + _2*10)(1,2,3));


        一个自制Lambda诞生了!和boost里一样好用,呃,好像似乎差不多啦... 因为boost里的lambda我也没怎么用过,不知道人家还有什么特异功能

    5/27/2007

    用C++ templates 实现Lambda(上)

        换工作以来一直用J2ME, 很久没碰C++了,非常怀念它的强大灵活。STL, templates, boost ... 工作就是这样,很无奈,为了混口饭吃就顾不了那么多了,用什么语言不要紧,只要给钱就行。公司有人原来用Java来了之后用C++,有人原来用C++来了之后用Java,有人原来用Java来了之后用C#... 晕死。 
        最近看到书上讲用C++ tempaltes 实现lambda, 还提到了boost,一时手痒就自己写了个,仿照boost里的 _1 。除了“_1”这两个字符外没有参考其它任何实现。基本原理和我之前写的expression templates实现差不多。 
        暂时只实现了一元变量,还不支持_2 _3,和强大到让人目瞪口呆的boost相比只是小儿科啦。什么时候有空再做 _2

      //////////////////////////////////////////////// 
     // lambda templates
    namespace XLambda { 
            template <typename T> 
            class CXLambdaLiteral { 
            public: 
                    CXLambdaLiteral(const T &t): m_data(t) {} 
                    template <typename V> 
                    inline V operator() (const V &x) const {return m_data;} 
            private: 
                    T m_data; 
            };

            class CXLambdaIdentity   { 
            public: 
                    template <typename V> 
                    inline V operator() (const V &x) const {return x;} 
            };

              template <class A,class B,class Op> 
            class CXLambdaBinOp  { 
            public: 
                    CXLambdaBinOp(const A &a,const B &b):m_a(a),m_b(b) {} 
                    template <class V> 
                    inline V operator() (const V &x) const 
                    {return Op::apply(m_a(x),m_b(x));} 
            private: 
                    A m_a; 
                    B m_b; 
            };

            template <class T> 
            class CXLambda   { 
            public: 
                    CXLambda(const T &t):m_t(t) {} 
                    CXLambda() {}; 
                    template<class V> 
                    inline V operator()(const V &x) const 
                    {return m_t(x);} 
            private: 
                    T m_t; 
            };

            ///////////////////////////////////////////// 
            struct XOpAdd { 
                    template<typename V> 
                    inline static V apply(const V&x, const V &y) { 
                            return x+y; 
                    } };

            template <typename A, typename B> 
            CXLambda<CXLambdaBinOp<CXLambda<A>, CXLambda<B>, XOpAdd> > 
                    operator +(const CXLambda<A> &a,const CXLambda<B> &b) 
            { 
                    typedef CXLambdaBinOp<CXLambda<A>, CXLambda<B>, XOpAdd>  LamT; 
                    return CXLambda<LamT>(LamT(a,b)); 
            }

     

            template <typename A, typename B> 
            CXLambda<CXLambdaBinOp<CXLambda<A>, CXLambda<CXLambdaLiteral<B> >, XOpAdd> > 
                    operator +(const CXLambda<A> &a,const B &b) 
            { 
                    typedef CXLambdaBinOp<CXLambda<A>, CXLambda<CXLambdaLiteral<B> >, XOpAdd>  LamT; 
                    return CXLambda<LamT>(LamT(a,CXLambdaLiteral<B>(b))); 
            }

            template <typename A, typename B> 
            CXLambda<CXLambdaBinOp<CXLambda<B>, CXLambda<CXLambdaLiteral<A> >, XOpAdd> > 
                    operator +(const A &a,const CXLambda<B> &b) 
            { 
                    typedef CXLambdaBinOp<CXLambda<B>, CXLambda<CXLambdaLiteral<A> >, XOpAdd>  LamT; 
                    return CXLambda<LamT>(LamT(b,CXLambdaLiteral<A>(a))); 
            }

            ///////////////////////////////////////////// 
            struct XOpMultiply { 
                    template<typename V> 
                    inline static V apply(const V&x, const V &y) { 
                            return x*y; 
                    } };

            template <typename A, typename B> 
            CXLambda<CXLambdaBinOp<CXLambda<A>, CXLambda<B>, XOpMultiply> > 
                    operator *(const CXLambda<A> &a,const CXLambda<B> &b) 
            { 
                    typedef CXLambdaBinOp<CXLambda<A>, CXLambda<B>, XOpMultiply>  LamT; 
                    return CXLambda<LamT>(LamT(a,b)); 
            }  

            template <typename A, typename B> 
            CXLambda<CXLambdaBinOp<CXLambda<A>, CXLambda<CXLambdaLiteral<B> >, XOpMultiply> > 
                    operator *(const CXLambda<A> &a,const B &b) 
            { 
                    typedef CXLambdaBinOp<CXLambda<A>, CXLambda<CXLambdaLiteral<B> >, XOpMultiply>  LamT; 
                    return CXLambda<LamT>(LamT(a,CXLambdaLiteral<B>(b))); 
            }

                    template <typename A, typename B> 
            CXLambda<CXLambdaBinOp<CXLambda<B>, CXLambda<CXLambdaLiteral<A> >, XOpMultiply> > 
                    operator *(const A &a,const CXLambda<B> &b) 
            { 
                    typedef CXLambdaBinOp<CXLambda<B>, CXLambda<CXLambdaLiteral<A> >, XOpMultiply>  LamT; 
                    return CXLambda<LamT>(LamT(b,CXLambdaLiteral<A>(a))); 
            }

            //减法和除法可以依样画葫芦

            //一元操作符++ 等 和函数如sin cos log, 也比较简单 可以参考之前的expression template 

          #define _1 CXLambda<CXLambdaIdentity>()
    }

            //////////////////////////////////////////////// 
           //使用测试 
            using namespace XLambda;
           
    vector<
    int> t;
            for(int i=0;i<10;i++)
                 t.push_back(i); 

           //vector中的值就会根据这个计算式改变了! 
            transform(t.begin(),t.end(),t.begin(),1000 + 100 * _1 + _1*10); 
            //或 
            transform(t.begin(),t.end(),t.begin(), _1 * _1 * _1);  


        以后会实现 _2, 如果我不是太懒的话。

     

    2/13/2007

    Expression Templates 代码实现

    ////////////////////////////////////////////////////////////////////////// 
    // 曾经根据Todd Veldhuizen的论文 Expression Templates 写的一份代码实现,
    // http://osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html

    // 不包括矩阵计算部分

    namespace

    XExp
    {
        #include <math.h> 

        //constant expression template 
        template <class T>
           
    class CXExpLiteral
        {
           
    public:
                CXExpLiteral(
    const T &t):m_data(t) {}
               
    template <class V>
                   
    inline V operator() (const V &x) const {return m_data;}
           
    private:
                T m_data;
        };

        //variable expression(the 'x' in a fomular) template 
        template
    <class T>
           
    class CXExpIdentity
        {
           
    public:
               
    template <class V>
                   
    inline V operator() (const V &x) const {return x;}
        };

        //binary operator template 
        template
    <class A,class B,class Op>
           
    class CXBinExpOp
        {
           
    public:
                CXBinExpOp(
    const A &a,const B &b):m_a(a),m_b(b) {}
               
    template <class V>
                   
    inline V operator() (const V &x) const
                {
    return Op::apply(m_a(x),m_b(x)); }

           
    private:
                A m_a;
                B m_b;
        };

        //unary operator template 
        template
    <class A,class Op>
           
    class CXUnaExpOp
        {
           
    public:
                CXBinExpOp(
    const A &a):m_a(a) {}
               
    template <class V>
                   
    inline V operator() (const V &x) const
                {
    return Op::apply(m_a(x)); }

            private:
                A m_a;
        };

        //static polymorphic interface template (this is only my own notion, maybe not a standard common concept)
        template
    <class T>
           
    class CXExp
        {
           
    public:
                CXExp(
    const T &t):m_t(t) {}
                CXExp() {};

               //static polymorphic interface(like a virtual function)

               
    template<class V>
                   
    inline V operator()(const V &x) const
                {
    return m_t(x); }

            private:
               
    T m_t;
       
    };

        //utility
        //function template to create a constant expression 
     
        template <class V>
           
    inline CXExp<CXExpLiteral<V> >
       
    mk_literal(const V &l)   { return CXExpLiteral<V>(l); }

        //the variable expression (the 'x' in a fomular again)
        typedef
    CXExp<CXExpIdentity> ExpX;

        //function template to evaluate the end expression
        template
    <class Exp,class V>
       
    V xeval(const CXExp<Exp> &exp,const V&x) { return exp(x); }

        ////////////////////////////////////////////////////////////////////////// 
        //binary operator
       
    //macro definition for the binary operator and the binary expression template class
       
    #define
    OP_BIN(_name,_op) \
           
    struct XOp##_name { \
               
    template<class V> \
               
    inline static V apply(const V &x,const V &y) \
               
    { return x _op y;} }; \
           
    template <class A,class B> \
           
    CXExp<CXBinExpOp<CXExp<A>,CXExp<B>,XOp##_name> > \ 
            
    operator _op(const CXExp<A> &a,CXExp<B> &b) { \
               
    typedef CXBinExpOp<CXExp<A>,CXExp<B>,XOp##_name> ExpT; \
               
    return CXExp<ExpT>(ExpT(a,b)); }

            OP_BIN(Divid,/)
           
    OP_BIN(Multipy,*)
           
    OP_BIN(Add,+)
           
    OP_BIN(Sub,-)
           
    //...

        //////////////////////////////////////////////////////////////////////////
        //unary operator
        #define OP_UNA_FUNC(_fun)                                     \
           
    struct XOp##_fun {                                             \
               
    inline static double apply(double x)                     \
               
    { return _fun(x);} };                                       \
           
    template <class A>                                              \
           
    CXExp<CXUnaExpOp<CXExp<A>,XOp##_fun> >        \
           
    _fun(const CXExp<A> &a) {                                  \
           
    typedef CXUnaExpOp<CXExp<A>,XOp##_fun> ExpT;  \ 
            
    return CXExp<ExpT>(ExpT(a)); }

            OP_UNA_FUNC(log)
           
    OP_UNA_FUNC(log10)
           
    OP_UNA_FUNC(sin)
           
    //...
    }

    //////////////////////////////////////////////////////////////////////////
    /* usage

        ExpX x; 
        cout << xeval((mk_literal(1.0)+x)/sin(x),1.2);

    */