确定性时的虚函数开销(c ++)

时间:2016-02-10 17:31:15

标签: c++ polymorphism

我知道虚函数本质上是vtable中包含的函数指针,由于间接等原因使得多态调用变慢。 但是当呼叫是确定性的时候,我想知道编译器优化。 确定性,我指的是以下情况:

  1. 对象是值而不是引用,因此不存在多态:
  2. struct Foo
    {
        virtual void DoSomething(){....}
    };
    
    int main()
    {
        Foo myfoo;
        myfoo.DoSemthing();
        return 0;
    }
    
    1. 引用无子女课程:
    2. struct Foo
      {
          virtual void DoSomething();
      };
      struct Bar : public Foo
      {
         virtual void DoSomething();
      };
      
      int main()
      {
          Foo* a = new Foo();
          a->DoSomething(); //Overhead ? a doesn't seem to be able to change nature.
      
          Foo* b = new Bar();
          b->DoSomething(); //Overhead ? It's a polymorphic call, but b's nature is deterministic.
      
          Bar* c = new Bar();
          c->DoSomething(); //Overhead ? It is NOT possible to have an other version of the method than Bar::DoSomething
          return 0;
      }
      

2 个答案:

答案 0 :(得分:9)

在第一种情况下,这不是虚拟呼叫。编译器将直接向Foo::DoSomething()发出呼叫。

在第二种情况下,它更复杂。首先,它最好是链接时间优化,因为对于特定的转换单元,编译器不知道还有谁可能从该类继承。您遇到的另一个问题是共享库,如果没有您的可执行文件知道任何相关内容,它们也可能继承。

一般而言,这是一种编译器优化,称为虚函数调用消除 devirtualization ,并且在某种程度上是一个活跃的研究领域。有些编译器在某种程度上做到了,有些编译器根本没做。

请参阅GCC(g ++),-fdevirtualize-fdevirtualize-speculatively。这些名字暗示着保证的质量水平。

答案 1 :(得分:2)

在Visual Studio 2013中,即使行为是确定性的,也不会优化虚函数调用。

例如,

#include <iostream>

static int counter = 0;

struct Foo
{
    virtual void VirtualCall() { ++counter; }
    void RegularCall() { ++counter; }
};

int main()
{
    Foo* a = new Foo();
    a->VirtualCall(); //Overhead ? a doesn't seem to be able to change nature.
    a->RegularCall();
    std::cout << counter;
    return 0;
}

虚拟呼叫的机器代码如下所示:

a->VirtualCall()

  0001b 8b 01        mov     eax, DWORD PTR [ecx]
  0001d ff 10        call    DWORD PTR [eax]

常规调用的机器代码显示函数是内联的 - 没有函数调用:

 a->RegularCall()

  00         inc     DWORD PTR _counter