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



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

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

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

显然,编译器无法做到这一点,因为只有在链接时才会清楚是否调用了特定的虚函数(假设是静态链接——显然动态链接无法做到这一点)。我对链接器不够熟悉,无法判断编译器是否能够以这样一种方式发出虚函数表,即链接器可以选择性地省略表中单个未使用的项。

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

注意,当编译器可以在编译时确定调用目标时,这与用直接调用替换虚函数调用是不同的。我知道有些编译器可以做到这一点,但这是另一种情况,因为函数实际上被调用了,它是虚拟函数分派的开销被删除了。在我的例子中,我希望删除未调用的函数的整个代码。

如果我能够控制所有的类定义,我就可以手动消除所有没有被调用的虚函数。但这在使用库时是不现实的。

这是可以做的事情与"链接时间优化"或"整个程序优化"?有编译器可以成功地做到这一点吗?

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

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

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

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

edit @curiousguy提出了一个编译器能够更自由地进行优化的情况,即链接器可以知道没有外部代码知道该类。这方面的一个例子是具有文件作用域的类

相关内容

  • 没有找到相关文章

最新更新