同一对象重复调用虚函数优化:能否仅单次访问虚函数表?
问题:虚函数表访问次数优化分析
给定代码
抽象类定义
class Base { public: virtual void f() = 0; virtual ~Base() = default; };
目标函数
void function (Base& x, bool flag1, bool flag2, bool flag3) { if(flag1) x.f(); if(flag2) x.f(); if(flag3) x.f(); }
主函数场景
int main() { Base* x = /* load from shared lib*/; bool flag1 = getchar() == '1'; bool flag2 = getchar() == '2'; bool flag3 = getchar() == '3'; function(*x, flag1, flag2, flag3); return 0; }
问题描述
在调用函数void function (Base& x, bool flag1, bool flag2, bool flag3)时,即便三个flag均为true,是否可期望仅访问一次虚函数表?即编译器能否仅从表中查找一次函数地址,后续两次调用复用该地址?
注:从共享库加载实例仅为示例,用于排除函数内联的可能性。
回答
可以期望编译器仅访问一次虚函数表并复用函数地址,但这属于编译器的优化行为,并非C++标准强制要求。
具体原因如下:
- 在
function函数的执行周期内,x作为Base&引用,其绑定的对象动态类型不会发生改变(代码中无修改对象类型的逻辑,且默认是单线程无外部干扰的场景),因此虚函数f()的地址是固定不变的。 - 编译器可以通过**公共子表达式消除(CSE)**优化,将从虚函数表中获取
f()地址的操作提取到所有条件判断之前,仅执行一次,后续满足条件的调用直接复用已获取的函数地址。 - 题目中排除内联的场景不影响该优化,因为虚表地址的提取优化与函数内联无关,只要编译器能确定对象的动态类型在函数内保持稳定,就可以触发该优化。
补充说明:如果存在多线程场景,且有其他线程可能修改x绑定对象的动态类型,编译器会因无法保证地址稳定性而放弃该优化,但本题的代码场景不存在这种情况。
内容的提问来源于stack exchange,提问作者Ian Gaspariunas
相关产品推荐
相关产品推荐

