【问题标题】:Overhead with std::functionstd::function 的开销
【发布时间】:2016-02-26 03:01:22
【问题描述】:

我看到很多人建议不要使用std::function<>,因为它是一种重量级的机制。有人可以解释一下为什么会这样吗?

【问题讨论】:

标签: c++ function c++11 c++14


【解决方案1】:

std::function 是一个类型擦除类。

它获取任何构造它的内容,并删除所有内容,除了:

  • 使用有问题的签名调用(可能有隐式转换)
  • 销毁
  • 复制
  • 还原为准确的原始类型

可能

  • 移动

这涉及一些开销。典型的质量不错的std::function 将进行小对象优化(如小字符串优化),避免在使用的内存量较小时进行堆分配。

一个函数指针将适合那里。

但是,仍然存在开销。如果您使用兼容的函数指针初始化std::function,而不是直接调用有问题的函数指针,您执行虚函数表查找,或调用其他函数,然后调用函数指针。

对于 vtable 实现,可能是缓存未命中,指令缓存未命中,然后是指令缓存未命中。使用函数指针,指针可能存储在本地,直接调用,可能导致指令缓存未命中。

除此之外,实际上编译器比std::functions 更好地理解函数指针:许多编译器可以在内联或整个程序优化期间确定指针是常量值。我从来没有见过用std::function 实现这一目标的人。

对于较大的对象(比如在一个实现中大于sizeof(std::string)),堆分配也由std::function 完成。这是另一个成本。对于函数指针和引用封装,标准保证SOO。


直接存储 lambda 而不将其存储在 std::function 中甚至比函数指针更好:在这种情况下,正在运行的代码隐含在 lambda 的类型中。这使得代码在调用它时计算出将发生的事情变得微不足道,并且对编译器来说内联变得容易。

仅在需要时进行类型擦除。

【讨论】:

  • 保证函数指针和reference_wrappers的小对象优化。
  • @T.C. std::function 是否提到了对函数的引用?我在 cppreference 上看不到任何内容(显然,这不是决定性的)。快速测试表明它可以由一个构建并且工作正常,但我不知道这是否证明了很多。引用是否简单地转换为指针?无论哪种方式,我都希望在某处提到引用的情况。
  • @underscore_d 构造函数按值取值,所以总是衰减的。
【解决方案2】:

在底层,std::function 通常使用类型擦除(here 是对如何实现它的一种简化解释)。将函数对象存储在 std::function 对象内的成本可能涉及堆分配。调用函数对象的成本通常是通过指针加上虚函数调用的间接方式。此外,虽然编译器在这方面做得越来越好,但虚函数调用通常会抑制函数的内联。

话虽如此,我建议使用std::function,除非您通过测量知道成本太高(通常当您负担不起堆分配时,您的函数将在需要非常低延迟的地方多次调用,等等.),因为编写简单的代码比过早地优化要好。

【讨论】:

    【解决方案3】:

    根据实现的不同,std::function 会由于使用类型 easure 而增加一些开销。它们是其他一些实现,例如 Don Clugston 的快速委托,具有 C++11 实现 here。请注意,它使用 UB 来生成尽可能快的委托,但仍然非常便携。

    【讨论】:

      【解决方案4】:

      如果您想要类型擦除,它是适合这项工作的工具,几乎可以肯定不是您的瓶颈,也不是您可以更快编写的东西。

      但是,有时在确实不需要时使用类型擦除可能很诱人。这就是画线的地方。例如,如果您只想在本地保留一个 lambda,那么它可能不是正确的工具,您应该使用:

      auto l = [](){};
      

      同样,对于您不打算键入擦除的函数指针 - 只需使用函数指针类型。

      您也不需要对来自<algorithm> 或您自己的等价物的模板进行类型擦除,因为根本不需要异构函子类型共存。

      【讨论】:

        【解决方案5】:

        不是这样的。

        简而言之,除非您对程序进行概要分析并表明它过于重量级,否则它不会太重量级。因为显然你没有(否则你会知道这个问题的答案),我们可以有把握地得出结论,它实际上一点也不重量级。

        在断定它太慢之前,您应该始终配置文件。

        【讨论】:

        • 这不是一个有用的答案。 OP 正在询问 为什么 可能是这种情况,并且没有多少分析可以回答这样的 why 问题。你还愚蠢地声称因为 OP 没有配置文件,所以它不是太重量级;这是不合逻辑的。这是一匹高大的马,你骑上去只是为了用 Hoare 的格言击中某人的头。
        猜你喜欢
        • 1970-01-01
        • 2014-06-24
        • 1970-01-01
        • 2013-02-24
        • 1970-01-01
        • 1970-01-01
        • 2014-09-23
        • 1970-01-01
        • 2014-01-08
        相关资源
        最近更新 更多