我应该在 C++ 中使用 std::function 还是函数指针?
在C++中实现回调函数时,我是否还应该使用C风格的函数指针:
When implementing a callback function in C++, should I still use the C-style function pointer:
void (*callbackFunc)(int);
或者我应该使用 std::function:
Or should I make use of std::function:
std::function< void(int) > callbackFunc;
推荐答案
简而言之,除非有理由不使用,否则请使用 std::function
.
函数指针的缺点是不能捕获某些上下文.例如,您将无法将 lambda 函数作为捕获某些上下文变量的回调传递(但如果它不捕获任何上下文变量,它将起作用).因此,调用对象的成员变量(即非静态)也是不可能的,因为需要捕获对象(this
-pointer).(1)
Function pointers have the disadvantage of not being able to capture some context. You won't be able to for example pass a lambda function as a callback which captures some context variables (but it will work if it doesn't capture any). Calling a member variable of an object (i.e. non-static) is thus also not possible, since the object (this
-pointer) needs to be captured.(1)
std::function
(自 C++11 起)主要用于存储一个函数(传递它不需要存储它).因此,如果您想将回调存储在例如成员变量中,这可能是您的最佳选择.而且如果你不存储它,它也是一个不错的首选"尽管它的缺点是在调用时引入了一些(非常小的)开销(因此在非常关键的性能情况下它可能是一个问题,但在大多数情况下它不应该).它非常通用":如果您非常关心一致和可读的代码,并且不想考虑您所做的每一个选择(即想要保持简单),请使用 std::function
对于您传递的每个函数.
std::function
(since C++11) is primarily to store a function (passing it around doesn't require it to be stored). Hence if you want to store the callback for example in a member variable, it's probably your best choice. But also if you don't store it, it's a good "first choice" although it has the disadvantage of introducing some (very small) overhead when being called (so in a very performance-critical situation it might be a problem but in most it should not). It is very "universal": if you care a lot about consistent and readable code as well as don't want to think about every choice you make (i.e. want to keep it simple), use std::function
for every function you pass around.
考虑第三种选择:如果您要实现一个小函数,然后通过提供的回调函数报告某些内容,请考虑一个模板参数,它可以是任何可调用的对象,即一个函数指针,一个函子,一个 lambda,一个 std::function
,......这里的缺点是你的(外部)函数变成了一个模板,因此需要在标题中实现.另一方面,您可以获得可以内联回调调用的优势,因为您的(外部)函数的客户端代码看到"了对回调的调用将提供可用的确切类型信息.
Think about a third option: If you're about to implement a small function which then reports something via the provided callback function, consider a template parameter, which can then be any callable object, i.e. a function pointer, a functor, a lambda, a std::function
, ... Drawback here is that your (outer) function becomes a template and hence needs to be implemented in the header. On the other hand you get the advantage that the call to the callback can be inlined, as the client code of your (outer) function "sees" the call to the callback will the exact type information being available.
带有模板参数的版本示例(对于 pre-C++11,编写 &
而不是 &&
):
Example for the version with the template parameter (write &
instead of &&
for pre-C++11):
template <typename CallbackFunction>
void myFunction(..., CallbackFunction && callback) {
...
callback(...);
...
}
如下表所示,它们各有优缺点:
As you can see in the following table, all of them have their advantages and disadvantages:
函数ptr | std::function | 模板参数 | |
---|---|---|---|
可以捕获上下文变量 | no1 | 是 | 是 |
没有调用开销(见评论) | 是 | no | 是 |
可以内联(见评论) | no | no | 是 |
可以存放在一个类成员中 | 是 | 是 | no2 |
可以在header之外实现 | 是 | 是 | no |
不支持 C++11 标准 | 是 | no3 | 是 |
可读性很好(我认为) | no | 是 | (是) |
(1) 存在克服此限制的解决方法,例如将附加数据作为进一步的参数传递给您的(外部)函数:myFunction(..., callback, data)
将调用 callback(data)
.这是 C 风格的带参数回调",这在 C++ 中是可能的(顺便说一下,在 WIN32 API 中大量使用)但应该避免,因为我们在 C++ 中有更好的选择.
(1) Workarounds exist to overcome this limitation, for example passing the additional data as further parameters to your (outer) function: myFunction(..., callback, data)
will call callback(data)
. That's the C-style "callback with arguments", which is possible in C++ (and by the way heavily used in the WIN32 API) but should be avoided because we have better options in C++.
(2) 除非我们谈论的是类模板,即存储函数的类是模板.但这意味着在客户端,函数的类型决定了存储回调的对象的类型,这在实际用例中几乎从来不是一个选项.
(3) 对于 C++11 之前的版本,使用 boost::function
相关文章