为什么 vtable 不能包含重复的函数?
Why can't a vtable contain duplicate functions?
想象一个项目,其中有一个界面 class 如下所示:
struct Interface
{
virtual void f()=0;
virtual void g()=0;
virtual void h()=0;
};
假设在其他地方,有人希望创建一个 class 实现此接口,为此 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 禁止它。
这样的优化是无效的,因为...
// somewhere-in-another-galaxy.hpp
struct X : S {
virtual void f();
};
// somewhere-in-another-galaxy.cpp
include <iostream>
void X::f() {
std::cout << "Hi from a galaxy far, far away! ";
}
如果编译器实现了您的优化,则此代码将无法运行。
Interface* object = new X;
object->g();
我的翻译单元的编译器不知道你的 class 内部实现,所以对于 g() 和 h() 它只是放入我的 class' 虚函数 table引用您 class' VFT 中的相应条目。
想象一个项目,其中有一个界面 class 如下所示:
struct Interface
{
virtual void f()=0;
virtual void g()=0;
virtual void h()=0;
};
假设在其他地方,有人希望创建一个 class 实现此接口,为此 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 禁止它。
这样的优化是无效的,因为...
// somewhere-in-another-galaxy.hpp
struct X : S {
virtual void f();
};
// somewhere-in-another-galaxy.cpp
include <iostream>
void X::f() {
std::cout << "Hi from a galaxy far, far away! ";
}
如果编译器实现了您的优化,则此代码将无法运行。
Interface* object = new X;
object->g();
我的翻译单元的编译器不知道你的 class 内部实现,所以对于 g() 和 h() 它只是放入我的 class' 虚函数 table引用您 class' VFT 中的相应条目。