快速业务通道

C++回调函数(callback)与仿函数(functor)的异同

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-29

回调函数(callback)与仿函数(functor)很多时候从用途上来看很相似,以致于我们经常 将它们相提并论。例如:

inline bool compare(int a, int b)
{
   return a > b;
}
 
struct comparer {
  bool operator()(int a, int b) const {
     return a > b;
  }
};
 
void main()
{
   std::vector<int> vec, vec2;
   std::sort(vec.begin(), vec.end(), compare);
   std::sort(vec2.begin(), vec2.end(), comparer());
}

仿函数(functor)之所以称为仿函数,是因为这是一种利用某些类对象支持operator()的 特性,来达到模拟函数调用效果的技术。

如果这里vec, vec2这两个vector的内容一样,那么从执行结果看,使用回调函数compare 与使用仿函数comparer是一样的。

那么,我们应该用回调,还是用仿函数?

很多人都说用仿函数吧,回调函数是丑陋的,代码不太象C++风格。

但其实问题的本质不是在代码风格上,仿函数与回调函数各有利弊,不能一概而论。

仿函数(functor)的优点

我的建议是,如果可以用仿函数实现,那么你应该用仿函数,而不要用回调。原因在于:

仿函数可以不带痕迹地传递上下文参数。而回调技术通常使用一个额外的void*参数传递 。这也是多数人认为回调技术丑陋的原因。

更好的性能。

仿函数技术可以获得更好的性能,这点直观来讲比较难以理解。你可能说,回调函数申明 为inline了,怎么会性能比仿函数差?我们这里来分析下。我们假设某个函数func(例如上 面的std::sort)调用中传递了一个回调函数(如上面的compare),那么可以分为两种情况 :

func是内联函数,并且比较简单,func调用最终被展开了,那么其中对回调函数的调用也 成为一普通函数调用(而不是通过函数指针的间接调用),并且如果这个回调函数如果简单 ,那么也可能同时被展开。在这种情形下,回调函数与仿函数性能相同。

func是非内联函数,或者比较复杂而无法展开(例如上面的std::sort,我们知道它是快 速排序,函数因为存在递归而无法展开)。此时回调函数作为一个函数指针传入,其代码亦 无法展开。而仿函数则不同。虽然func本身复杂不能展开,但是func函数中对仿函数的调用 是编译器编译期间就可以确定并进行inline展开的。因此在这种情形下,仿函数比之于回调 函数,有着更好的性能。并且,这种性能优势有时是一种无可比拟的优势(对于std::sort就 是如此,因为元素比较的次数非常巨大,是否可以进行内联展开导致了一种雪崩效应)。

仿函数(functor)不能做的?

话又说回来了,仿函数并不能完全取代回调函数所有的应用场合。例如,我在 std::AutoFreeAlloc中使用了回调函数,而不是仿函数,这是因为AutoFreeAlloc要容纳异质 的析构函数,而不是只支持某一种类的析构。这和模板(template)不能处理在同一个容器 中支持异质类型,是一个道理。

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号