Почему vtable не может содержать повторяющиеся функции?

Представьте себе проект, в котором есть класс интерфейса, такой как:

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();}
};

Тогда было бы правильной оптимизацией для создания vtable для S, чьи записи все указатели на 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 запрещает его.
1 ответ

Такая оптимизация недействительна, потому что...

// 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! ";
}
</iostream>

Если компилятор реализует вашу оптимизацию, этот код не будет работать.

Interface* object = new X;
object->g();

Компилятор моей единицы перевода не знает о внутренней реализации вашего класса, поэтому для g() и h() он просто помещает ссылки на таблицы виртуальных функций моего класса на соответствующие записи в вашем классе VFT.

licensed under cc by-sa 3.0 with attribution.