小编典典

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

all

在 C++ 中实现回调函数时,是否仍应使用 C 风格的函数指针:

void (*callbackFunc)(int);

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

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

阅读 44

收藏
2022-08-20

共1个答案

小编典典

简而言之,std::function除非您有理由不使用,否则请使用。

函数指针的缺点是 无法捕获 某些上下文。例如,您将无法将 lambda
函数作为捕获某些上下文变量的回调传递(但如果它不捕获任何变量,它将起作用)。因此,调用对象的成员变量(即非静态)也是不可能的,因为this需要捕获对象(-pointer)。(1)

std::function(自 C++11 起)主要是 存储
一个函数(传递它不需要存储它)。因此,如果您想将回调存储在成员变量中,这可能是您的最佳选择。但是,如果您不存储它,它也是一个很好的“首选”,尽管它的缺点是在调用时会引入一些(非常小的)开销(因此在性能非常关键的情况下,它可能是一个问题,但在大多数情况下它不应该)。它非常“通用”:如果您非常关心一致和可读的代码,并且不想考虑您所做的每一个选择(即希望保持简单),请使用std::function您传递的每个函数。

考虑第三种选择:如果您要实现一个小函数,然后通过提供的回调函数报告某些内容,请考虑一个 模板参数 ,它可以是 任何可调用对象
,即函数指针、仿函数、lambda, a std::function, …
缺点是您的(外部)函数成为模板,因此需要在标题中实现。另一方面,您可以获得对回调的调用可以内联的优势,因为您的(外部)函数的客户端代码“看到”对回调的调用将获得可用的确切类型信息。

带有模板参数的版本示例(写&而不是&&C++11 之前的版本):

template <typename CallbackFunction>
void myFunction(..., CallbackFunction && callback) {
    ...
    callback(...);
    ...
}

如下表所示,它们都有其优点和缺点:

函数指针 标准::函数 模板参数
可以捕获上下文变量 没有1 是的 是的
没有通话开销(见评论) 是的 是的
可以内联(见评论) 是的
可以存储在类成员中 是的 是的 没有2
可以在标头之外实现 是的 是的
不支持 C++11 标准 是的 没有3 是的
可读性很好(我的观点) 是的 (是的)

(1) 存在克服此限制的解决方法,例如将附加数据作为进一步参数传递给您的(外部)函数:myFunction(..., callback, data)将调用callback(data). 那是 C 风格的“带参数的回调”,这在 C 中是可能的(顺便说一句,在 WIN32 API
中大量使用),但应该避免,因为我们在 C
中有更好的选择。

(2) 除非我们谈论的是类模板,即存储函数的类是模板。但这意味着在客户端,函数的类型决定了存储回调的对象的类型,这几乎不是实际用例的选项。

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

2022-08-20