vftable性能损失与switch语句

eee*_*aii 28 c++ performance virtual

C++问题在这里.我有一个系统,我将拥有数百个给定超类的迷你子类.他们都会有一个"foo"方法做某事.或者......我将有一个带有一个名为"type"的整数的类,并使用一个巨大的switch语句来决定当我foo时该做什么.

性能是一个重要的考虑因素.非常重要.

问题是,使用switch语句与让C++通过vftable实现它的性能优势/惩罚是什么?如果我将它作为switch语句,我可以将常见的foo放在switch语句的顶部,而不太常见的那些放在底部,希望能够快速进行比较.尝试使用vftable获得这样的效果必然会依赖于编译器,即使我可以弄清楚如何做到这一点......

另一方面,如果没有这些丑陋的switch语句,我的代码将更容易处理.

chr*_*ock 13

如果我将它作为switch语句,我可以将常见的foo放在switch语句的顶部,而不太常见的那些放在底部,希望能够快速进行比较.

一个switch语句通常编译成跳转表,而不是块if-else为您的问题暗示条件句.在实践中,虚拟表和switch跳转表应具有相似的性能,但如果您真的担心的话,请进行测试.

  • +1"测试,看看有什么更快".结果取决于实现,因此测量是唯一的查找方法. (3认同)
  • +1:无论如何,开关基本上都会变成vtable. (2认同)

小智 12

在虚拟机设计领域已经有一些关于这个主题的研究.通常,switch语句会更快,许多虚拟机使用切换语义而不是虚拟查找.从理论上讲,人们会认为虚拟表 - 一个恒定时间算法 - 会更快,但我们必须检查硬件如何看待虚拟表.

switch语句更易于编译器内联.这是一个很大的考虑因素,调用虚函数的实际行为是最小的,但是,推送和弹出整个堆栈帧是必要的,因为编译器不知道在运行时将调用哪个函数.

虽然现代架构在预测虚拟呼叫方面变得更好,但在switch语句中分支预测和硬件预取应该更容易.

许多使用虚拟分派的代码都需要使用基于堆的分配方案.动态内存分配是很多C++应用程序的瓶颈.

  • 它的 false 比 virtual 需要堆。自动对象的工作原理都是一样的。以及池化对象。您可以覆盖 new 并使其甚至从静态表中分配。 (2认同)

edA*_*a-y 5

编译器决定如何处理 switch 语句,但它们使用了一些基本技术。

  1. if-else 二进制排序:比较是作为一系列 if-else 完成的,但以类似二进制排序的方式进行,因此性能与在 N 个项目的映射中查找相当
  2. 跳转表:如果项目足够接近,将生成一个地址表。然后查找是在恒定时间内进行的

case 语句位于 switch 语句中的位置在任何一种情况下都没有区别。

与直接调用相比,虚函数有一定的开销。它涉及额外的偏移量和指针查找。对于除了最极端的性能考虑之外的所有情况,此成本可以忽略不计。与交换机相比,开销不在于虚拟查找,而在于函数调用本身。因此,在每种情况下仅调用函数的 switch 语句的执行效果与虚拟函数基本相同。

因此,与虚拟函数调用相比,switch 语句(带有跳转表)的“调度语义”本质上几乎是无关紧要的。如果所有“foo”方法都相对较小并且可以内联,则 switch 语句将开始执行得更好。switch 的另一个优点是您可以将通用代码放在 switch 之前并获得更好的寄存器/堆栈优化。

然而,存在大量的维护开销。这应该是您此时最关心的问题。为什么?因为代码中的性能瓶颈不太可能是切换登录,甚至不是函数调用,而是其他东西。在解决其他问题之前,解决这些低级性能问题是没有意义的。因此,请坚持使用目前提供更易于维护的代码的那个。