为什么执行时方法解析比编译时解析更快?

Fel*_*lix 1 c++ oop virtual

在学校,我们关于virtualC++中的函数,以及如何在执行时而不是编译时解决(或找到匹配,我不知道术语是什么 - 我们不是用英语学习).老师还告诉我们,编译时分辨率比执行时间快得多(并且它是有意义的).但是,快速实验会暗示其他情况.我已经建立了这个小程序:

#include <iostream>
#include <limits.h>

using namespace std;

class A {
    public:
    void f() {
        // do nothing
    }
};

class B: public A {
    public:
    void f() {
        // do nothing
    }
};

int main() {
    unsigned int i;
    A *a = new B;
    for (i=0; i < UINT_MAX; i++) a->f();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我编写了上面的程序并命名了它normal.然后,我修改A为这样:

class A {
    public:
    virtual void f() {
        // do nothing
    }
};
Run Code Online (Sandbox Code Playgroud)

编译并命名virtual.这是我的结果:

[felix@the-machine C]$ time ./normal 

real    0m25.834s
user    0m25.742s
sys 0m0.000s
[felix@the-machine C]$ time ./virtual 

real    0m24.630s
user    0m24.472s
sys 0m0.003s
[felix@the-machine C]$ time ./normal 

real    0m25.860s
user    0m25.735s
sys 0m0.007s
[felix@the-machine C]$ time ./virtual 

real    0m24.514s
user    0m24.475s
sys 0m0.000s
[felix@the-machine C]$ time ./normal 

real    0m26.022s
user    0m25.795s
sys 0m0.013s
[felix@the-machine C]$ time ./virtual 

real    0m24.503s
user    0m24.468s
sys 0m0.000s
Run Code Online (Sandbox Code Playgroud)

似乎有一个稳定的~1秒的差异有利于虚拟版本.为什么是这样?


相关与否:双核奔腾@ 2.80Ghz,两次测试之间没有额外的应用程序运行.Archlinux与gcc 4.5.0.正常编译,如:

$ g++ test.cpp -o normal
Run Code Online (Sandbox Code Playgroud)

此外,-Wall也不会吐出任何警告.


编辑:我把我的程序分成了A.cpp,B.cppmain.cpp.此外,我使f()(两个A::f()B::f())函数实际上做了一些事情(x = 0 - x其中x是一个public int成员A,初始化为1 A::A()).将其编译为六个版本,这是我的最终结果:

[felix@the-machine poo]$ time ./normal-unoptimized 

real    0m31.172s
user    0m30.621s
sys 0m0.033s
[felix@the-machine poo]$ time ./normal-O2

real    0m2.417s
user    0m2.363s
sys 0m0.007s
[felix@the-machine poo]$ time ./normal-O3

real    0m2.495s
user    0m2.447s
sys 0m0.000s
[felix@the-machine poo]$ time ./virtual-unoptimized 

real    0m32.386s
user    0m32.111s
sys 0m0.010s
[felix@the-machine poo]$ time ./virtual-O2

real    0m26.875s
user    0m26.668s
sys 0m0.003s
[felix@the-machine poo]$ time ./virtual-O3

real    0m26.905s
user    0m26.645s
sys 0m0.017s
Run Code Online (Sandbox Code Playgroud)

虚拟时,未经优化的速度仍然快1秒,我觉得有点奇怪.但这是一个很好的实验,并感谢你们所有人的答案!

小智 11

一旦vtable在缓存中,实际执行某些操作的虚拟和非虚拟函数之间的性能差异非常小.在使用C++开发软件时,您通常不应该关注自己.正如其他人所指出的那样,在C++中对未经优化的代码进行基准测试是毫无意义的.

  • 现实世界中+1,@ Felix,担心这样的事情被称为*微优化*,而不是优秀程序员浪费时间做的事情 - 编程大型系统很难实现.您真正担心虚拟调用(以及其他微优化)的速度的唯一时间是您每秒调用该函数数百万次. (3认同)

Mar*_*tos 6

分析未经优化的代码几乎毫无意义.使用-O2产生有意义的结果.使用-O3甚至会导致更快的代码,但除非你编译它可能不会产生一个现实的结果A::f,并B::f分别对main(即,在不同的编译单元).

根据反馈,甚至-O2可能过于激进.2 ms的结果是因为编译器完全优化了循环.直接电话不是那么快; 事实上,应该很难观察到任何明显的差异.将实现移动f到单独的编译单元以获取实数.定义类在.h,但定义A::fB::f在自己的.cc文件.

  • @Felix优化器可能已经完全删除了函数调用(也许是循环) - 你必须使函数具有全局副作用来防止这种情况. (2认同)