当前位置: 首页 > 知识库问答 >
问题:

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

孟承嗣
2023-03-14

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

void (*callbackFunc)(int);

或者我应该使用std::函数:

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

共有3个答案

鞠泰平
2023-03-14
匿名用户

使用std::function存储任意可调用对象。它允许用户提供回调所需的任何上下文;普通函数指针不能。

如果出于某种原因需要使用普通的函数指针(可能是因为您想要一个C兼容的API),那么您应该添加一个< code>void * user_context参数,这样它至少可以(尽管不方便)访问没有直接传递给函数的状态。

宋宏毅
2023-03-14

void (*回调Func)(int);可能是一个C风格的回调函数,但它是一个非常无法使用的糟糕设计函数。

设计良好的C风格回调看起来像< code>void (*callbackFunc)(void*,int); -它有一个< code>void*来允许执行回调的代码维护函数之外的状态。不这样做将迫使调用者全局存储状态,这是不礼貌的。

std::函数

现在,回调系统的客户端通常需要设置资源并在创建和删除回调时处理它们,并了解回调的生命周期。void(*call back)(void*, int)不提供这个。

有时这可以通过代码结构(回调具有有限的生命周期)或通过其他机制(取消注册回调等)获得。

std::function提供了一种有限生命周期管理的方法(当对象的最后一个副本被遗忘时,它就会消失)。

一般来说,我会使用< code>std::function,除非有明显的性能问题。如果他们这样做了,我会首先寻找结构变化(而不是每像素回调,如何基于你传递给我的lambda生成一个扫描线处理器?这应该足以将函数调用开销降低到微不足道的水平。).然后,如果它继续存在,我将基于最快的可能委托编写一个< code >委托,看看性能问题是否会消失。

我通常只对遗留API使用函数指针,或者创建C接口,以便在不同编译器生成的代码之间进行通信。当我实现跳转表、类型擦除等时,我也将它们用作内部实现细节:当我既生产又消费它,并且不向外部公开它以供任何客户端代码使用时,函数指针做了我所需要的一切。

请注意,您可以编写将std::f的包装器

鲁涵映
2023-03-14

简而言之,使用< code>std::function除非你有理由不这样做。

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

< code>std::function(从C 11开始)主要是存储一个函数(传来传去不需要存储)。因此,如果你想把回调存储在一个成员变量中,这可能是你最好的选择。但是,如果您不存储它,这也是一个很好的“第一选择”,尽管它的缺点是在被调用时会引入一些(非常小的)开销(因此,在性能非常关键的情况下,这可能是一个问题,但在大多数情况下应该不会)。它非常“通用”:如果你非常关心代码的一致性和可读性,并且不想考虑你做的每一个选择(也就是说,想保持简单),那么对你传递的每一个函数使用< code>std::function。

考虑第三种选择:如果您要实现一个小函数,然后通过所提供的回调函数报告一些东西,那么考虑一个模板参数,它可以是任何可调用的对象,即函数指针、仿函数、lambda、< code>std::function,...这里的缺点是你的(外部)函数变成了一个模板,因此需要在头文件中实现。另一方面,您可以获得回调调用可以内联的优势,因为您的(外部)函数的客户端代码“看到”回调调用将获得确切的类型信息。

带有模板参数的版本示例(写入<代码>

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

如下表所示,它们都有各自的优点和缺点:

 类似资料:
  • 本文向大家介绍c++11 符号修饰与函数签名、函数指针、匿名函数、仿函数、std::function与std::bind,包括了c++11 符号修饰与函数签名、函数指针、匿名函数、仿函数、std::function与std::bind的使用技巧和注意事项,需要的朋友参考一下 一、符号修饰与函数签名 1、符号修饰 编译器将c++源代码编译成目标文件时,用函数签名的信息对函数名进行改编,形成修饰名。G

  • 本文向大家介绍理解C++编程中的std::function函数封装,包括了理解C++编程中的std::function函数封装的使用技巧和注意事项,需要的朋友参考一下 先来看看下面这两行代码: 这两行代码是从Cocos2d-x中摘出来的,重点是这两行代码的定义啊。std::function这是什么东西?如果你对上述两行代码表示毫无压力,那就不妨再看看本文,就当温故而知新吧。 std::functi

  • 问题内容: 我对于应该使用javascript创建对象的方式感到困惑。似乎至少有两种方法。一种是使用对象文字符号,而另一种是使用构造函数。有一个相对于另一个的优势吗? 问题答案: 如果您没有与对象相关联的行为(即,如果对象只是数据/状态的容器),则可以使用对象文字。 运用KISS原则。如果除了简单的数据容器之外不需要任何其他内容,请使用简单的文字。 如果要向对象添加行为,则可以使用构造函数并在构造

  • 我将指向。很好用。之后,解压ant并设置与ant相关的环境变量,在键入后,得到以下错误消息 我搜索了这个论坛。看起来一个解决方案是将Java指向JDK,而不是JRE。我不确定这是否应该是解决办法。换句话说,一般来说,JAVA_HOME应该指向哪一个?JDK还是JRE?

  • 问题内容: 我来自Java背景,是python的新手。我有几个脚本,它们共享一些与读取和写入文件有关的应用程序特有的辅助功能。有些功能与阅读有关,有些与写作有关。在寻找正确的方法时,我看到了这一点:Python中的静态方法? 他在回答中提到: 最后,请谨慎使用staticmethod!在极少数情况下,Python中需要使用静态方法,而我已经看到它们使用了很多次,而使用单独的“顶层”函数会更加清楚。