关于虚函数的成本

ful*_*ton 9 c++ virtual

如果我在一个循环中调用虚拟函数1000次,我将遭受vtable查找开销1000次或仅一次吗?

小智 8

编译器可能能够对其进行优化 - 例如,以下(至少在概念上)可以轻松优化:

Foo * f = new Foo;
for ( int i = 0; i < 1000; i++ ) {
   f->func();
}
Run Code Online (Sandbox Code Playgroud)

但是,其他情况更难:

vector <Foo *> v;
// populate v with 1000 Foo (not derived) objects
for ( int i = 0; i < v.size(); i++ ) {
   v[i]->func();
}
Run Code Online (Sandbox Code Playgroud)

相同的概念优化是适用的,但编译器要查看起来要困难得多.

底线 - 如果您真的关心它,请在启用所有优化的情况下编译代码并检查编译器的汇编程序输出.


Sam*_*ell 6

Visual C++编译器(至少通过VS 2008)不会缓存vtable查找.更有趣的是,它不会直接调度对象的静态类型被密封的虚方法.但是,虚拟调度查找的实际开销几乎总是可以忽略不计.您有时会看到命中的地方在于,C++中的虚拟调用不能像托管VM中的直接调用那样被替换.这也意味着没有虚拟呼叫的内联.

确定应用程序影响的唯一真正方法是使用分析器.

关于原始问题的具体细节:如果您调用的虚拟方法非常简单,虚拟调度本身会产生可测量的性能影响,那么该方法足够小,以至于vtable将在整个循环中保留在处理器的缓存中.即使从vtable中拉出函数指针的汇编指令执行1000次,性能影响也会小得多(1000 * time to load vtable from system memory).