优化的虚拟呼叫成本

时间:2015-10-06 12:24:14

标签: c++

当指向的类型始终相同时,我对虚拟调用的成本有疑问:

class Base
{
    Base() {};
    virtual void Func() = 0;
};

class Derived
    : public Base
{
    Derived() : Base() {};
    void Func() { /* Do something */ };
};

int main()
{
    Base* base = new Derived;

    for (int i = 0; i < 1000; ++i)
    {
        base->Func();
    }

    return 0;
}

编译器会优化此虚拟呼叫吗?

5 个答案:

答案 0 :(得分:2)

GCC与-O3似乎无法优化虚拟通话。

https://goo.gl/TwZD6T

.L5  
    movq    (%rdx), %rdx
    cmpq    Derived::Func(), %rdx
    je  .L3
    movq    %rbp, %rdi
    call    *%rdx
    subl    $1, %ebx
    jne .L11

这会进行函数指针比较,如果不相等,则执行间接函数调用。

答案 1 :(得分:2)

很难优化功能的虚拟性。您无法在正确的编译时知道虚拟不会产生任何影响。只有在链接时才能解决这个问题。

更有问题的是你甚至可能无法知道,因为你可以动态加载实现另一个可能覆盖虚函数的子类的共享库。

基本上这种优化需要非常智能的链接时间优化,因为这可能是非常小的增益。

答案 2 :(得分:1)

像GCC这样的VC ++并没有优化呼叫。 使用Visual Studio 2013在发布模式下使用/ O2标志构建:

    base->Func();
010B12D2  mov         eax,dword ptr [esi] //load V-Table 
010B12D4  mov         ecx,esi //load this pointer into ecx  
010B12D6  call        dword ptr [eax]  //call the first function in the V-Table.

<强> 编辑: 你的问题实际上证明了一些非常好esi持有this。如何解除引用this给出V-Table?好吧,因为V-Table是第一个&#34;变量&#34;多态对象具有内存。所以汇编方面,*this()实际上产生了对第一个函数的调用,*(this+sizeof(void*))()调用了V-Table中的第二个函数,依此类推。
它就像宣布你的班级一样

class A{
   VTABLE vtable;
   //rest of the variables.
}

答案 3 :(得分:1)

这取决于编译器的智能性;也许它可以优化,也许不是。它也是一个实现细节 - 您更关心代码的整体性能,而不是像这样的具体细节。衡量您的表现并决定是否需要优化,如果需要,您的方法。

如果您真的关心这样的代码,您可以选择使用C ++ 11关键字gsub,并对循环外的类型进行测试,而不是仅在循环内使用vtable dispatch。

答案 4 :(得分:0)

编译器无法优化此虚拟调用,因为Derived的vtable符号在外部可见,并且可以在运行时使用共享对象和LD_PRELOAD环境变量覆盖。

如果您使用-fvisibility=hidden参数,我认为它应该能够优化通话。