2012-09-12 80 views
3

对于下面的代码示例,指针num_ptr执行方法“递增”的速度比本地变量num要慢得多。我认为它与虚拟方法有关,但我不明白为什么。请帮忙解释一下。我试图从这个例子中了解性能问题。局部变量vs指针的性能

#include <iostream> 

const long long iterations_count = 1000000; 

// a number interface 
struct number {   
    virtual void increment() = 0; 
}; 

struct concrete_number:number 
{ 
    long long a; 
    concrete_number(long long p){ 
     a = p; 
    } 
    void increment() 
    { 
     a+=1; 
    } 
}; 

int main() { 

    concrete_number num(0); 
    concrete_number* num_ptr = &num; 

    for (long long i = 0; i < iterations_count; i++) { 
     num.increment(); 
    } 

    for (long long i = 0; i < iterations_count; i++) { 
     num_ptr->increment(); 
    } 
    std::getchar(); 
} 
+1

虚拟方法似乎是最可能的原因。当你在* object *上调用虚拟方法时,可以在编译时决定调用哪个版本;当你在一个*指针*上调用它时,决定只能在运行时完成(当然,如果编译器可以计算出来,可以在编译时做出这个决定,但肯定会出现这种情况)。 – DCoder

+1

我很惊讶你收到慢的表现结果。编译器应该能够优化它,因为在这种情况下,即使存在虚函数调用,指针也是与派生类型相同的类型(即在num_ptr-> increment中没有涉及基类指针)。 – sashang

+0

嗨sashang,我的确很惊讶。此程序是使用静态链接构建的,我使用Visual Studio 2012发行模式和优化选项/ O2/Oi/Ot –

回答

7

num.increment();解决了静态,num_ptr->increment();将动态解析(该功能是通过动态调度调用,因为它是virtual)。

但是,在完全优化之后,编译器应该产生类似的结果。

没有optmizations:

num.increment(); 
00341453 lea   ecx,[num] 
00341456 call  concrete_number::increment (341186h) 

VS

num_ptr->increment(); 
00341490 mov   eax,dword ptr [num_ptr] 
00341493 mov   edx,dword ptr [eax] 
00341495 mov   esi,esp 
00341497 mov   ecx,dword ptr [num_ptr] 
0034149A mov   eax,dword ptr [edx] 
0034149C call  eax 
0034149E cmp   esi,esp 
003414A0 call  @ILT+340(__RTC_CheckEsp) (341159h) 

有了优化,至少对我来说,这两个调用内联。

+0

当您说它动态解析时,是否意味着我的程序尝试在运行时查找vtable以确定哪里是派生最多的方法实现?而我的问题与他们的内存位置(堆栈或堆)无关?提前致谢。 –

+0

@BryanFok是的.. –

+0

@BryanFok也没有堆。你只有堆栈对象。 –