在C++中实现回调函数时,是否应该仍然使用C样式的函数指针:
void (*callbackFunc)(int);或者我应该使用std::function:
std::function< void(int) > callbackFunc;发布于 2014-09-15 13:39:58
void (*callbackFunc)(int);可能是一个C风格的回调函数,但它的设计非常糟糕,无法使用。
一个设计良好的C风格回调看起来像void (*callbackFunc)(void*, int); --它有一个void*,允许执行回调的代码维护函数之外的状态。不这样做会迫使调用方全局存储状态,这是不礼貌的。
在大多数实现中,std::function< int(int) >的开销都略高于int(*)(void*, int)调用。然而,有些编译器很难内联。有一些std::function克隆实现可以与函数指针调用开销(请参阅“最快可能的委托”等)竞争,这些实现可能会进入库。
现在,回调系统的客户端通常需要在创建和删除回调时设置资源并将其释放,并且需要知道回调的生存期。void(*callback)(void*, int)不提供此功能。
有时,这可以通过代码结构(回调具有有限的生存期)或其他机制(注销回调等)提供。
std::function为有限的生命周期管理提供了一种方法(当对象被遗忘时,对象的最后一份副本就会消失)。
通常,除非性能问题明显,否则我会使用std::function。如果是这样的话,我会首先寻找结构变化(而不是每像素回调,不如根据您传递给我的lambda生成scanline处理器如何?)这应该足以将函数调用开销降低到微不足道的水平。)。然后,如果它仍然存在,我将编写一个基于最快可能的委托的delegate,并查看性能问题是否消失。
我通常只对遗留API使用函数指针,或者创建C接口,以便在不同编译器生成的代码之间进行通信。在实现跳转表、类型擦除等时,我还将它们用作内部实现的详细信息:当我同时生成和使用跳转表,并且没有对外公开它供任何客户端代码使用时,函数指针可以满足我的所有需要。
请注意,您可以编写包装器,将std::function<int(int)>转换为int(void*,int)样式的回调,前提是有适当的回调生存期管理基础设施。因此,作为对任何C风格回调生命周期管理系统的冒烟测试,我会确保包装std::function工作得相当好。
发布于 2014-09-15 13:06:43
使用std::function存储任意可调用对象。它允许用户提供回调所需的任何上下文;普通函数指针不提供。
如果您确实出于某种原因需要使用普通函数指针(可能是因为您想要一个与C兼容的API),那么您应该添加一个void * user_context参数,这样它至少可以(尽管不方便)访问不直接传递给该函数的状态。
发布于 2014-09-15 13:03:06
避免std::function的唯一原因是支持对此模板缺乏支持的遗留编译器,该模板已在C++11中引入。
如果不需要支持预C++11语言,那么使用std::function可以让调用方在实现回调时有更多的选择,这与“普通”函数指针相比是一个更好的选择。它为API的用户提供了更多的选择,同时为执行回调的代码抽象出他们实现的细节。
https://stackoverflow.com/questions/25848690
复制相似问题