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

Jan Swart:

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

void (*callbackFunc)(int);

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

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

简而言之,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) {
    ...
    callback(...);
    ...
}

正如您在下表中看到的,它们都有优点和缺点:

+-------------------+--------------+---------------+----------------+
|                   | function ptr | std::function | template param |
+===================+==============+===============+================+
| can capture       |    no(1)     |      yes      |       yes      |
| context variables |              |               |                |
+-------------------+--------------+---------------+----------------+
| no call overhead  |     yes      |       no      |       yes      |
| (see comments)    |              |               |                |
+-------------------+--------------+---------------+----------------+
| can be inlined    |      no      |       no      |       yes      |
| (see comments)    |              |               |                |
+-------------------+--------------+---------------+----------------+
| can be stored     |     yes      |      yes      |      no(2)     |
| in class member   |              |               |                |
+-------------------+--------------+---------------+----------------+
| can be implemented|     yes      |      yes      |       no       |
| outside of header |              |               |                |
+-------------------+--------------+---------------+----------------+
| supported without |     yes      |     no(3)     |       yes      |
| C++11 standard    |              |               |                |
+-------------------+--------------+---------------+----------------+
| nicely readable   |      no      |      yes      |      (yes)     |
| (my opinion)      | (ugly type)  |               |                |
+-------------------+--------------+---------------+----------------+

(1)存在克服此限制的解决方法,例如,将其他数据作为进一步的参数传递给您的(外部)函数:myFunction(..., callback, data)将调用callback(data)这就是C样式的“带参数的回调”,在C ++中是可行的(并且在WIN32 API中大量使用),但是应避免使用,因为我们在C ++中有更好的选择。

(2)除非我们在谈论类模板,否则存储函数的类就是模板。但这意味着在客户端,函数的类型决定了存储回调的对象的类型,对于实际使用案例,这几乎绝不是一种选择。

(3)对于C ++ 11之前的版本,请使用 boost::function

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

我应该在git别名脚本中使用`sh -c \“ ... \”`还是`“!f(){...;}; f”吗?

我应该在接口中声明变量还是在Objective-C Arc中使用属性?

我应该在 C++ 中使用 ExitThread() 还是从线程返回

我应该在POSIX shell中使用“ test”还是“ [”“]”?

我应该在JSFiddle中使用:after还是:: after?

我应该在“ this”中使用bind还是关闭别名?

我应该在 c 中使用哪些 i/o 函数

我应该在 F# 中使用子函数还是辅助函数?

我应该在C ++中将“使用名称空间”放在名称空间内部还是外部

我应该在Python 2.7中使用print语句还是函数?

我应该在OCaml递归函数中使用数组还是列表?

我应该在<Link>中使用onCLick = {}函数还是它周围的元素

我应该在函数中使参数如何可见?

我们应该在C#中使用String.format还是String.replace?

我应该在C#类中使用私有字段还是公共属性足够好?

我应该在这里使用哪种指针?

我应该在将二维数组作为 C 中参数的函数的头中使用什么语法

我应该在返回std :: vector的函数上使用std :: move吗?

我应该还是不应该在不同的c文件中包含相同的标头,而这些标头又在主文件中使用?

我应该在iOS开发中使用首选字体还是动态字体(系统)

我们应该在子进程中使用退出还是返回

我应该在组件中使用一个还是多个useEffect?

我们应该在Android中使用getPath还是getAbsolutePath

我应该在jQuerys文档中使用onclick还是click方法吗?

我应该在 Javascript 中使用多个变量还是单个对象?

我应该在JAX-RS中使用@QueryParam还是@BeanParam?

我应该在recyclerView中使用recyclerView还是有更好的方法?

我应该在AsyncTask中使用WeakReference <Context>还是Application Context?

我应该在KDE Plasma桌面环境中使用KUbuntu还是Ubuntu 16.04?