循环调用同一个虚函数的开销

Posted

技术标签:

【中文标题】循环调用同一个虚函数的开销【英文标题】:Overhead of calling the same virtual function in a loop 【发布时间】:2019-12-25 08:56:06 【问题描述】:

我有一些结构如下的代码:

doStuff2() 将通过Class1 指针调用。这将在循环中调用doStuff()。有多个类如Class3 所以Class2 将有多个模板实例。)

struct Class1

    virtual void doStuff2() = 0;

;

template<typename T> struct Class2 : public Class1

    virtual void doStuff()  /*code*/;

    void doStuff2() override 

        // Call this in a huge loop.
            doStuff();

    

;

struct Class3 : public Class2<SomeType>

    void doStuff() override final  /*code*/;

;

//...

void someFunc(Class1 *p_class1)

    p_class1->doStuff2();


我的问题:有没有办法以非虚拟方式调用doStuff(),所以没有开销?在Class2 中将其设为纯虚拟并在Class3 中设为最终版本会有帮助吗?

在这样的循环中调用同一个虚函数会不会有虚函数的所有性能问题?

【问题讨论】:

如果你真的需要runtime dispatch,你必须使用virtual,所以你需要付费。如果没有,请编写反映这一点的代码。我们经常看到要求降低虚拟通话速度的问题。您知道单个 vpointer 调用的真正开销是多少吗?您认为现实世界应用程序的其余部分需要什么?唯一真正有帮助的:测量你的最终代码!并且相信:编译器比你想象的要好得多! 我真的不确定为什么 /* code */ 而不是 minimal reproducible example 以及为什么没有意义的函数名称。 doStuff() 的实现是否应该让你在其中进行循环?还是您在谈论其他循环?为什么不在那里放一个循环?对于固定类型X,每个Class2&lt;X&gt; 有多少Class3s 样式类型?是否有多个Class2 模板? (Class2 是模板类,不是类;Class3 同时似乎代表类的类别,尽管命名模式相同,Class1 a 是唯一类型?) 哦,简短的版本是“您尝试过 CRTP 吗?”这些问题旨在解码 CRTP 是否可以工作,从您的描述中不清楚。 我认为你想优化一个不存在的瓶颈。在真实程序的上下文中,虚拟调度的成本低得可笑。即使您找到了一种以更快的速度删除虚拟调度的方法,性能提升也会非常有限,以至于不会节省您花在担心它上的时间。 @churill 有dispatch代码本身,然后就是缺少内联。 【参考方案1】:

cmets 对为什么这可能是过早的优化有一些很好的建议,但要直接回答您的问题:

有没有办法以非虚拟方式调用 doStuff() 所以没有开销?

如果你有一组固定的类型,那么你可以通过标记联合的方式运行时调度非虚拟方法,ala std::variant

using Class1 = std::variant<Class2<SomeType1>, Class2<SomeType2>>;
/*...*/
std::visit([](auto&& c)  c.doStuff(); , p_class1);

粗略地优化为一些不错的 C 风格切换:

switch (p_class1.class_type) 
    case CLASS2_SOMETYPE1:
         ((Class2<SomeType1>)p_class1).doStuff();
         break;
    /*...*/

在这样的循环中调用同一个虚函数会不会有虚函数的所有性能问题?

现代处理器非常擅长间接分支预测,因此您可能不会看到在循环中调用虚拟方法的开销很大。

【讨论】:

以上是关于循环调用同一个虚函数的开销的主要内容,如果未能解决你的问题,请参考以下文章

虚函数可以是内联函数吗?

vc 父类实现一个虚函数,子类继承并也实现这个虚函数,子类调用这个虚函数,父类这个虚函数会不会执行?

static函数如何调用虚函数

关于C++的虚函数在父类的内部调用

通过虚函数表调用虚函数与通过虚函数表(绕过访问权限控制)

如何能避免在调用子类对象的虚函数时调用父类的虚函数呢?