C++虚函数:链接器是否可以删除未调用的虚函数表中的条目?

sh-*_*sh- 11 c++ linker dead-code vtable compiler-optimization

这个问题是一种消除未使用的虚函数的后续问题,对我的兴趣不够深入.

问题:在定义具有虚函数的类时,编译器为虚函数表分配存储,并存储指向表中函数的指针.这会导致链接器保留这些函数的代码,无论它们是否被调用.即使编译器优化设置要求消除死代码,这也可能导致大量死代码保留在可执行文件中.

现在,如果在可执行文件中没有任何地方存在特定虚函数的调用(或者换句话说,访问虚函数表的相应槽),则可以从虚函数表中省略相应的函数指针,并且链接器将删除函数的代码,可能会进一步遗漏其他未引用的代码.

显然,这不能由编译器完成,因为它只在链接时变得清楚是否调用了特定的虚函数(假设静态链接 - 很明显它不能用动态链接完成).我对链接器不够熟悉,以便判断编译器是否能够以链接器可以选择性地忽略表中各个未使用的条目的方式发出虚函数表.

基本上,我的思路是这样的:虚函数表中的函数指针是对函数的引用,链接器使用该函数来确定函数的代码需要保留在可执行文件中.以类似的方式,虚函数调用是对从其虚函数被调用的类派生的所有虚函数表中的特定槽的引用.这种引用是否可以通过这样一种方式传递给链接器:当它没有引用时,它可以忽略虚函数表槽?

请注意,当编译器可以在编译时确定调用目标时,这与使用直接调用替换虚函数调用不同.我知道一些编译器可以做到这一点,但这是一个不同的情况,因为函数实际上被调用,并且它是被删除的虚函数调度的开销.在我的情况下,我希望删除未调用的函数的整个代码.

如果我可以控制所有类定义,我可以手动删除所有未调用的虚函数.但是在使用库时这是不现实的.

这可以通过"链接时间优化"或"整个程序优化"来完成吗?是否有成功的编译器?

Gre*_*rie 2

死代码的问题在于,从动态库的角度来看,编译器不可能确定代码是死的。可执行文件可以动态地包含使用死代码的库(派生自拥有死代码的类)。

除此之外,如果可执行文件是唯一进行函数调用的,那么在链接时更改 v 表的结构可能会很好地工作。但是,如果动态库进行任何调用,它会对 v 表有不同的理解,并且会调用错误的函数。

由于这些事实,并且从表面上看并没有获得太多(如果有的话)性能,优化链接器不太可能具有此功能。

虚拟函数的去虚拟化实际上与此有关,安全优化链接器只能去虚拟化极少数的函数调用。例如,如果它可以保证没有动态库可以在调用堆栈中发挥任何作用,则它只能对函数进行去虚拟化。

编辑@curiousguy提出了一种情况,编译器可以更加自由地进行优化,也就是说链接器可以知道没有外部代码知道该类。一个例子是具有文件作用域的类。