猿问

我应该在C ++中使用std :: function还是函数指针?

在C ++中实现回调函数时,我仍应使用C样式函数指针:


void (*callbackFunc)(int);

或者我应该使用std :: function:


std::function< void(int) > callbackFunc;


米琪卡哇伊
浏览 1543回答 3
3回答

跃然一笑

简而言之,std::function除非有理由不要使用。函数指针的缺点是无法捕获某些上下文。例如,您将无法通过lambda函数作为捕获某些上下文变量的回调(但是如果不捕获任何上下文变量,它将起作用)。因此也不可能调用对象的成员变量(即非静态的),因为this需要捕获对象(-pointer)。(1)std::function(因为C ++ 11)主要用于存储函数(将其传递就不需要存储它)。因此,如果要将回调存储在例如成员变量中,则可能是最佳选择。但是,如果您不存储它,那么它是一个不错的“首选”,尽管它的缺点是在调用时会引入一些(非常小的)开销(因此,在性能非常关键的情况下,这可能是个问题,但在大多数情况下它不应该)。这是非常“通用的”:如果您非常关心一致且易读的代码,又不想考虑所做的每一个选择(即想保持简单),请使用std::function传递的每个函数。考虑第三个选项:如果您要实现一个小的函数,然后通过提供的回调函数报告某些内容,请考虑一个template参数,该参数可以是任何可调用的对象,即函数指针,函子,lambda,一个std::function缺点是这里的(外部)函数成为模板,因此需要在标头中实现。另一方面,您得到的好处是可以内联对回调的调用,因为(外部)函数的客户端代码“看到”了对回调的调用,将提供确切的类型信息。具有模板参数的版本的示例(对于C ++ 11之前的版本,请写&而不是&&):template <typename CallbackFunction>void myFunction(..., CallbackFunction && callback) {&nbsp; &nbsp; ...&nbsp; &nbsp; callback(...);&nbsp; &nbsp; ...}正如您在下表中看到的,它们都有优点和缺点:+-------------------+--------------+---------------+----------------+|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| function ptr | std::function | template param |+===================+==============+===============+================+| can capture&nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; no(1)&nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; yes&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;yes&nbsp; &nbsp; &nbsp; || context variables |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |+-------------------+--------------+---------------+----------------+| no call overhead&nbsp; |&nbsp; &nbsp; &nbsp;yes&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;no&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;yes&nbsp; &nbsp; &nbsp; || (see comments)&nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |+-------------------+--------------+---------------+----------------+| can be inlined&nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; no&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;no&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;yes&nbsp; &nbsp; &nbsp; || (see comments)&nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |+-------------------+--------------+---------------+----------------+| can be stored&nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp;yes&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; yes&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; no(2)&nbsp; &nbsp; &nbsp;|| in class member&nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |+-------------------+--------------+---------------+----------------+| can be implemented|&nbsp; &nbsp; &nbsp;yes&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; yes&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;no&nbsp; &nbsp; &nbsp; &nbsp;|| outside of header |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |+-------------------+--------------+---------------+----------------+| supported without |&nbsp; &nbsp; &nbsp;yes&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp;no(3)&nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp;yes&nbsp; &nbsp; &nbsp; || C++11 standard&nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |+-------------------+--------------+---------------+----------------+| nicely readable&nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; no&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; yes&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; (yes)&nbsp; &nbsp; &nbsp;|| (my opinion)&nbsp; &nbsp; &nbsp; | (ugly type)&nbsp; |&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |+-------------------+--------------+---------------+----------------+(1)存在克服此限制的解决方法,例如,将其他数据作为进一步的参数传递给您的(外部)函数:myFunction(..., callback, data)will call callback(data)。这就是C样式的“带参数的回调”,这在C ++中是可行的(并且在WIN32 API中大量使用),但是应避免使用,因为我们在C ++中有更好的选择。(2)除非我们在谈论类模板,否则存储函数的类就是模板。但这意味着在客户端,函数的类型决定了存储回调的对象的类型,这在实际用例中几乎从来不是一个选择。(3)对于C ++ 11之前的版本,请使用 boost::function

白衣染霜花

使用std::function存储任意调用对象。它允许用户提供回调所需的任何上下文。一个普通的函数指针没有。如果由于某种原因(也许是因为您想要C兼容的API)而确实需要使用普通函数指针,则应添加一个void * user_context参数,以便至少有可能(尽管不方便)访问不直接传递给参数的状态。功能。
随时随地看视频慕课网APP
我要回答