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

回调函数(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)不能处理在同一个容器 中支持异质类型,是一个道理。

时间: 2024-12-21 11:06:16

C++回调函数(callback)与仿函数(functor)的异同的相关文章

C++中回调函数(CallBack)的用法分析_C 语言

本文实例分析了C++中回调函数(CallBack)的用法.分享给大家供大家参考.具体分析如下: 如果试图直接使用C++的成员函数作为回调函数将发生错误,甚至编译就不能通过. 其错误是普通的C++成员函数都隐含了一个传递函数作为参数,亦即"this"指针,C++通过传递this指针给其成员函数从而实现程序函数可以访问C++的数据成员.这也可以理解为什么C++类的多个实例可以共享成员函数却-有不同的数据成员.由于this指针的作用,使得将一个CALL-BACK型的成员函数作为回调函数安装时

浅谈jquery回调函数callback的使用_jquery

回调函数必须是全局函数或者静态函数,不可定义为某个特定的类的成员函数 callback函数在当前动画100%完成之后执行 复制代码 代码如下: $("p").hide(1000); alert("the paragraph is now hidden"); <!--未使用回调函数,段落未完全隐藏时就弹出信息--> $("p").hide(1000,function(){alert("the paragraph is now

理解javascript中的回调函数(callback)_javascript技巧

最近在看 express,满眼看去,到处是以函数作为参数的回调函数的使用.如果这个概念理解不了,nodejs.express 的代码就会看得一塌糊涂.比如: 复制代码 代码如下: app.use(function(req, res, next) {     var err = new Error('Not Found');     err.status = 404;     next(err); }); app是对象,use是方法,方法的参数是一个带参的匿名函数,函数体直接在后面给出了.这段代码

为什么Ajax调用后台Action,结果返回回调函数时,在js里没有进入回调函数?

问题描述 我在js里面通过ajax调用一个action,然后返回结果给回调函数,但是程序始终不进入回调函数callback,请问问题出在哪里了?<script type="text/javascript">function chooseFile(obj){$('uploadpictureForm').action = "${pageContext.request.contextPath}/page/uploadPicture.action";$('upl

jQuery的load()方法及其回调函数用法实例_jquery

本文实例讲述了jQuery的load()方法及其回调函数用法.分享给大家供大家参考.具体如下: 下面的js代码演示了jQuery的load()方法的使用,并演示了带回调函数(callback)的load方法的使用 <!DOCTYPE html> <html> <head> <script src="js/jquery.min.js"> </script> <script> $(document).ready(fun

JS中回调函数的写法

<!DOCTYPE HTML> <html><head>  <meta charset="GBK" /><title>回调函数(callback)</title> <script type="text/javascript" src="jquery-1.11.3.min.js"></script><script language="ja

Javascript基于AJAX回调函数传递参数实例分析_javascript技巧

本文实例讲述了Javascript基于AJAX回调函数传递参数的方法.分享给大家供大家参考,具体如下: 前面介绍了<javascript实现html页面之间参数传递的四种方法>,这里针对ajax参数传递做一分析. 在Javascript 中,特别是在AJAX中,回调函数常常是一个函数名,没有地方放入参数,如下面的AJAX代码,在成功后将调用回调函数callback,但callback是有参数的,如何把参数传进来呢? var callback = function(p1){ //do somet

jQuery 回调函数(callback)的使用和基础_jquery

还是先贴代码吧 复制代码 代码如下: <!DOCTYPE html> <html>     <head>         <meta charset="utf-8">         <title></title>         <script src="js/jquery.js"></script>     </head> <style> bo

socket编程callBack回调函数的问题!

问题描述 在这个demo里,建了一个服务器端的类ReceiveServerController,创建套接字时如下:CFSocketCreateWithNative(NULL,fd,kCFSocketAcceptCallBack,AcceptCallback,&context);其中回调函数是AcceptCallback,定义如下:staticvoidAcceptCallback(CFSocketRefs,CFSocketCallBackTypetype,CFDataRefaddress,cons