想象一个项目,在这个项目中有一个如下所示的接口类:
struct Interface
{
virtual void f()=0;
virtual void g()=0;
virtual void h()=0;
};
假设在其他地方有人希望创建一个实现此接口的类,其中
f
,g
,h
都做同样的事情。struct S : Interface
{
virtual void f() {}
virtual void g() {f();}
virtual void h() {f();}
};
优化S类的有效方法是生成一个vtable,其中所有条目都指向S::f的指针,从而节省对包装函数g和h的调用。
然而,打印vtable的内容显示这种优化并未执行:
S s;
void **vtable = *(void***)(&s); /* I'm sorry. */
for (int i = 0; i < 3; i++)
std::cout << vtable[i] << '\n';
0x400940
0x400950
0x400970
使用-O3
或-Os
编译没有效果,切换clang和gcc也没有用。
为什么会错过这个优化机会呢?
目前,我考虑并排除了以下猜测:
- vtable打印代码实际上输出的是垃圾数据。
- 性能提升被认为是无用的。
- ABI禁止它。
Interface
指定至少应有三个函数:f
、g
和h
来完全实现Interface
。由于某种原因,它们被设计成三个不同的函数,具有三个不同的名称。现在,您正在创建一个子类,在其中所有这些函数都执行完全相同的操作。您认为这是一个好的设计吗?答案是否定的,除非出现非常不寻常的情况。此外,我认为这样的“优化”几乎没有任何真正的改进,特别是由于内联。 - Mateusz Grzejekattack
,collide
,talk_to
。然后在'Dynamite'中,vtable条目应该都指向detonate
。 - PBS