boost bind及function的简单实现

boost bind及function的简单实现

前面在做 http server 的时候,需要做一个回调的接口,要求能够绑定类的函数以及普通的函数到这个回调里,对于这种应用要求,选择 boost 的 bind 和 function 是最合适不过了,但现在情况有些不同,我不准备在现在做的这个东西里加入 boost, 本着以造轮子为乐的精神,现在只能捋起袖子自己来搞一个。

大概原型

使用的时候一直没有太留意它们的实现,现在要做起来,发现也不是想像中那么轻而易举。这个东西做到最后要实现的效果就是设计一个泛型的 function holder,这个 holder 既能包装类的函数,又要能包装一般的函数,换言之就是能像下面一样来使用。

 

复制代码
#include <iostream>

using namespace std;

class cs
{
   public:
      
       int proc(double d) { cout << "mem func proc:" << d << endl; return (int)d;}
};


int Proc(double d)
{
   cout << "normal proc:" << d << endl;
   return (int)d;
}


int main()
{
   function fun = &Proc;
   fun(2.3);

   cs c;
   fun = bind(&cs::proc, &c);
   fun(3.3);

   return 0;
}
复制代码

简单实现

一开始你可能会想,piece of cake! 直接封装一个function就行了。

复制代码
template<class ret_type, class arg_type>
class function1: public copyable
{
    public:
        typedef ret_type (* NORM_PROC) (arg_type);

        function1(NORM_PROC proc = 0): fun_(proc){}

        ret_type operator() (arg_type arg) { fun_->operator()(arg); }

        private:

        NORM_PROC fun_;
};
复制代码

好,这个类可以封装一般的函数了,那类的函数呢?one more!

复制代码
template<class CS, class ret_type, class arg_type>
class function2: public copyable
{
    public:
        typedef ret_type (CS::* MEM_PROC)(arg_type);
        function2(CS* obj, MEM_PROC proc): obj_(obj), proc_(proc) {}

        ret_type operator() (arg_type arg) { return (obj_->*proc_)(arg); }

    private:
        CS* obj_;
     MEM_PROC proc_;
};
复制代码

很快我们就发现有问题了,function1和function2是两不同的模板类,bind()的时候没法处理:bind()返回的应该要是一个统一的类型。

怎么办呢?我们可能想到要抽取出一个基类来,思路是对的!但还有些细节要处理。

比如:bind()返回的是什么类型呢?function1,function2的基类吗?这好像做不到,不能直接返回object, 所以下面的做法是错的。

复制代码
template<class ret_type, class arg_type>
class function_base: public copyable
{
   public:
      virtual ~function_base(){}
      ret_type operator() (arg_type arg) = 0;
};

template<class CS, class ret_type, class arg_type>
class function2: public function_base<ret_type, arg_type>
{
    public:
     typedef ret_type (CS::* MEM_PROC)(arg_type);
        function2(CS* obj, MEM_PROC proc): obj_(obj), proc_(proc) {}

        ret_type operator() (arg_type arg) { return (obj_->*proc_)(arg); }

    private:
        CS* obj_;
     MEM_PROC proc_;
};

template<class CS, class ret_type, class arg_type>
function_base<ret_type, arg_type> bind(ret_type (CS::* proc)(arg_type), CS* pc)
{
    function2<CS, ret_type, arg_type> func_holder(pc, proc);
    return func_holder;   // object slicing
}
复制代码

那直接返回指针不就完了!

返回指针可行,但不好用,而且容易内存泄漏。解决的办法是对返回的指针再包一层,嗯,RAII.

等等,好像如果再包一层,就已经能直接隔开底下的function holder与具体的调用了啊!Perfect!

复制代码
template<class ret_type, class arg_type>
class function_base: public copyable
{
   public:
      virtual ~function_base() {}
      ret_type operator() (arg_type arg) = 0;
};

template<class ret_type, class arg_type>
class function1: public function_base<ret_type, arg_type>
{
       public:
        
          typedef ret_type (* NORM_PROC) (arg_type);
        
          function1(NORM_PROC proc = 0): fun_(proc){}

          ret_type operator() (arg_type arg) { fun_->operator()(arg); }
        
      private:
        
          NORM_PROC fun_;
 
};

template<class CS, class ret_type, class arg_type>
class function2: public function_base<ret_type, arg_type>
{
    public:
     typedef ret_type (CS::* MEM_PROC)(arg_type);
        function2(CS* obj, MEM_PROC proc): obj_(obj), proc_(proc) {}

        ret_type operator() (arg_type arg) { return (obj_->*proc_)(arg); }

    private:
        CS* obj_;
     MEM_PROC proc_;
};

template<class ret_type, class arg_type>
class functioin: public copyable
{
   public:
     
     function(function_base<ret_type, arg_type>* pf): _obj(pf) {}
     ret_type operator()(arg_typearg){fun_->operator()(arg);}

   private:
      function_base<ret_type, arg_type>* obj_;
};

template<class CS, class ret_type, class arg_type>
function<ret_type, arg_type> bind(ret_type (CS::* proc)(arg_type), CS* pc)
{
    return new function2<CS, ret_type, arg_type>(pc, proc);
}
复制代码

 

经过这样一包装,function类好像已经能够用来bind类的函数了, 也没那么难嘛!

但是,代码很差劲:

1) 没有处理内存释放。

2) 没有处理copy costructor , assignment operator()。

3) 普通函数还是不能直接赋值给function类。

 

再改一下function类:

复制代码
template<class ret_type, class arg_type>
class function
{
    public:
        typedef ret_type (* NORM_PROC) (arg_type);

        function(function_base<ret_type, arg_type>* fun): fun_(fun), ref_(new int(1)) {}

        function(NORM_PROC proc = 0): fun_(new function1<ret_type, arg_type>(proc)), ref_(new int(1)) {}

        ret_type operator() (arg_type arg) { fun_->operator()(arg); }

        ~function()
        {
            Release();
        }

        void Release()
        {
            *ref_ -= 1;
            if (*ref_ == 0)
            {
                delete ref_;
                delete fun_;
            }
        }

        function(const function& fun)
        {
            fun_ = fun.fun_;
            ref_ = fun.ref_;
            *ref_ += 1;
        }

        void operator=(const function& fun)
        {
            Release();
            fun_ = fun.fun_;
            ref_ = fun.ref_;
            *ref_ += 1;
        }

    private:

        int* ref_;
        function_base<ret_type, arg_type>* fun_;
};
复制代码

 

这样一来,终于能够正常使用了。
可以看到,为了使得function类能被 copy/assign,这里面使用引用计数来控制内存的释放问题,上面的实现比较简单,也不是线程安全的,只是满足了基本的使用需求,具体的代码参看这里

代码写得较快,暂且就这样了,不知道 boost 是怎样实现的?得找个时间研究研究。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值