使用gprof分析我的C++代码,我发现我的大部分时间花在一遍又一遍地调用一个虚拟方法上.该方法本身很短,如果它不是虚拟的,可能会内联.
有什么方法可以加快这一点,而不是将其重写为不是虚拟的?
你确定时间与呼叫有关吗?可能是成本本身的功能吗?如果是这种情况,简单地内联可能会使您的分析器中的功能消失,但您不会看到太多的加速.
假设真的是进行如此多虚拟调用的开销,那么在不使虚拟非事物的情况下你可以做的事情是有限的.
如果呼叫有时间/标志之类的早期出现,那么我将经常使用两级方法.检查内联非虚拟调用,只有在必要时才调用特定于类的行为.
例如
class Foo { public: inline void update( void ) { if (can_early_out) return; updateImpl(); } protected: virtual void updateImpl( void ) = 0; };
是时候花在实际的函数调用中,还是在函数本身中?
虚拟函数调用是明显比非虚拟调用慢,因为虚拟呼叫需要额外的解引用.(谷歌为'vtable',如果你想阅读所有毛茸茸的细节.)更新:事实证明维基百科的文章并不坏.
但是,"明显地"在这里意味着一些指令如果它消耗了总计算的很大一部分,包括在被调用函数中花费的时间,那么这听起来像是一个考虑非虚拟化和内联的奇妙场所.
但是在近20年的C++中,我认为我从未见过这种情况真的发生过.我很想看到代码.
如果虚拟呼叫确实是瓶颈,请试试CRTP.
请注意,"虚拟"和"内联"并不是对立的 - 方法可以是两者.如果编译器可以在编译时确定对象的类型,编译器将很乐意内联虚函数:
struct B { virtual int f() { return 42; } }; struct D : public B { virtual int f() { return 43; } }; int main(int argc, char **argv) { B b; cout << b.f() << endl; // This call will be inlined D d; cout << d.f() << endl; // This call will be inlined B& rb = rand() ? b : d; cout << rb.f() << endl; // Must use virtual dispatch (i.e. NOT inlined) return 0; }
[更新:rb
在编译时无法识别某些真正的动态对象类型 - 感谢MSalters]
如果可以在编译时确定对象的类型但是函数不可内联(例如,它很大或在类定义之外定义),则将非虚拟地调用它.