2015-09-01 19 views
6

Wyobraźmy sobie projekt, w którym istnieje klasa interfejs jak poniżej:Dlaczego vtable nie może zawierać duplikatów funkcji?

struct Interface 
{ 
    virtual void f()=0; 
    virtual void g()=0; 
    virtual void h()=0; 
}; 

Załóżmy, że gdzieś indziej, ktoś chce utworzyć klasę wykonawczą tego interfejsu, dla którego f, g, h wszystkim zrobić to samo .

struct S : Interface 
{ 
    virtual void f() {} 
    virtual void g() {f();} 
    virtual void h() {f();} 
}; 

Wtedy byłby to ważny optymalizacji w celu wygenerowania vtable dla S którego wpisy są wszystkie wskaźniki S::f, oszczędzając w ten sposób wywołanie funkcji owijania g i h.

Drukowanie zawartości vtable pokazuje jednak, że ta optymalizacja nie jest wykonywana:

S s; 
void **vtable = *(void***)(&s); /* I'm sorry. */ 
for (int i = 0; i < 3; i++) 
    std::cout << vtable[i] << '\n'; 

0x400940
0x400950
0x400970

Kompilacja z -O3 lub -Os nie ma efekt, podobnie jak przełączanie między klangiem i gcc.

Dlaczego ta możliwość optymalizacji została pominięta?

W chwili obecnej są to przypuszczenia, że ​​mam uznawane (i odrzucone):

  1. vtable kod druk rzeczywiście drukuje śmieci.
  2. Poprawa wydajności uważana jest za bezwartościową.
  3. ABI to zabrania.
+8

Optymalizacja ta będzie widoczna dla kodu zgodne, ponieważ wskaźniki do funkcji składowych byłoby porównać równe. –

+0

Może wydawać się naiwny, ale dla mnie * funkcja nazywająca 'f' * nie jest' f' sama. Byłoby więc dziwnie, gdyby wskaźniki do funkcji członków były równe, nie sądzisz? –

+2

@David Schwartz: llvm jest znany z tego, że może wykonywać takie czynności, jak kod inline za pomocą wskaźników funkcji. przypuszczalnie może również inline ciała 'f' w' G' i 'h' również? To nie jest to samo, co optymalizacja zaproponowana przez OP. Zgaduję, że ta optymalizacja nie jest w praktyce bardzo ważna, więc nikt się nie przejmuje? Czuje się jak „wskaźnik do funkcji członka-” porównującego równe problem mógł być albo wykrywane przez kompilator lub średnia może być modyfikowana w celu umożliwienia funkcji optymalizacji Anyways w ten sam sposób, że kopiowanie ellision jest dozwolone –

Odpowiedz

2

Taka optymalizacja nie jest ważny, ponieważ ...

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

Jeśli kompilator realizuje swoje optymalizację ten kod nie będzie działać.

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

Kompilator mojego jednostki tłumaczeniowej nie wie o swojej wewnętrznej implementacji klasy więc dla g() i H() to właśnie stawia w mojej klasie funkcje wirtualne odniesień stół do odpowiednich wpisów w swojej klasie VFT .

+0

Problem nie polega na tym, że "twój kompilator nie wie o mojej wewnętrznej implementacji w klasie" - nawet jeśli " g() 'jest zaimplementowany w nagłówku, jest to przypadek" inne kompilatory nie są wymagane, aby kontynuować poprawianie optymalizacji mojego kompilatora "(co może zrobić przez przesłonięcie' g', gdy nadpisuje 'f'). – PBS

+1

Inna uwaga: podczas pakowania definicji 'S' w anonimowym obszarze nazw i włączania' -O2', gcc * robi * scalanie wszystkich wpisów vtable (tym samym użyczając wiarygodnie tej odpowiedzi). – PBS

Powiązane problemy