仿函数实际上比函数指针更快吗?

use*_*484 58 c++ function-pointers inlining function-object

根据Scott Meyers的说法,C++在C上闪耀的一个领域是函数对象比函数指针更快.他说这是因为函数对象是内联的,这会提高速度.

我有两个问题:

  1. 我们如何验证函数对象实际上是内联的?我们能否在实践中验证这一点?

  2. 函数对象的内联是否依赖于我们使用的编译器,还是所有编译器的行为都是这样的?

Yak*_*ont 76

C++和C标准为编译器留下了一大堆自由.编译器可以在每条指令之间自由计数到10亿,或者只有在整数具有素数值时才能这样做.

体面的"真实"编译器不这样做.这是一个实施质量问题.

将函数对象内联到类似于std::sort每个真正的编译器所做的事情.在这些情况下检测需要内联的内容非常容易,因为类型信息带有需要内联的代码.

使用函数指针这样做更难.使用函数指针执行此操作,其中所有内容都已转换为void*char*指针更难.

这样做的结果是,在实践中,qsort对C++风格的调用进行C风格的调用std::sort可以带来很大的优势std::sort.

qsort大致2倍慢于std::sort,如图这里,在分选随机排列整数可笑的简单情况.

检查实际的汇编代码输出主要是一个细节,并且很少有回报.通过具体的实际示例,您可以了解实际影响有多大.

clang,gcc和MSVC中的所有3个能够std::sort显着快于他们的速度qsort.由于这是一个简单的优化,虽然优化函数指针到内联调用不是,你期望较少的主要编译器不比这更好qsort.

  • 传播类型信息和内嵌模板更容易,因为模板基本上是"复制和粘贴"专用的.这是一种代码生成机制.(缺点是更大的二进制文件和编译时间,就像你复制了代码一样.) (3认同)
  • 我同意@usr,不同之处在于使用模板,实例可以更好地适应调用情况的细节,而不是编译一次的库函数,因为后者必须针对各种情况运行相同的代码.如果用C语言实现`qsort`而不是库函数,那么编译器可以优化每个实例,尽管使用了函数指针(只要在每次调用时都明确指出哪个函数是指向的) to),结果将与C++中`std :: sort`的结果一样快. (2认同)
  • @YvesgereY不,`std :: sort`有一个(一组)重载,使用`<`进行比较,另一个(一组)重载使用传入的函数对象进行比较.传递`std :: less <void> {}`(`less <void>`是一个调用`<`的无状态函数对象)作为第二个的函数对象导致与第一个只使用`<的第一个相同的性能`(忽略一些奇怪的角落案例).直接使用`<`不是为什么它更快,因为使用间接的`<`仍然同样快.脚注:( set of)引用了在C++ 17中添加的并行`std :: sort`. (2认同)

πάν*_*ῥεῖ 18

  1. 我们如何验证函数对象实际上是内联的?我们能否在实践中验证这一点?

当然,检查最终发出的汇编程序代码.

  1. 内联函数对象取决于我们使用的编译器,或者所有编译器的行为都是这样的?

它在很大程度上取决于编译器实现和使用的优化级
所以不,不能保证特定的编译器(链接器)表现如此.

但是,通过函数指针调用不能内联.


根据他的说法,函数对象是内联的,因此速度会有所提高.

IMO "内联函数对象"应该更好地阅读(或听到,我不知道该引用的来源):

通过函数指针调用时,函数对象可以内联.

  • @ user7140484 _"所以我们可以得出结论,斯科特迈耶斯的陈述不是一个绝对真理吗?"_你会信任谁来告诉_"绝对真理"_ ?? 大多数现代c ++编译器可能都是这样,但仍然依赖于优化级别和编译器决定内联代码的其他情况. (9认同)