Ci sono casi in cui una classe dichiara metodi virtuali e il compilatore non ha bisogno di usare un vptr?

StackOverflow https://stackoverflow.com/questions/2336107

  •  22-09-2019
  •  | 
  •  

Domanda

Mi chiedevo se esiste una possibile ottimizzazione in cui il compilatore non ha bisogno di assegnare un vptr ad un oggetto istanziato, anche se il tipo di oggetto è una classe con metodi virtuali.

Ad esempio considerare:

#include <iostream>
struct FooBase
{
  virtual void bar()=0;
};

struct FooDerived : public FooBase
{
  virtual void bar() { std::cout << "FooDerived::bar()\n"; }
};

int main()
{
   FooBase* pFoo = new FooDerived();
   pFoo->bar();

  return 0;
}

In questo esempio il compilatore sa sicuramente quello sarà il tipo di pFoo al momento della compilazione, in modo che non ha bisogno di utilizzare un vptr per pFoo, giusto? ci sono casi più interessanti in cui il compilatore può evitare di utilizzare un vptr?

È stato utile?

Soluzione

Sulla di Andrew Stein risposta , perché penso che anche voi volete sapere quando la cosiddetta 'testa di esecuzione di funzioni virtuali' può essere evitato. (L'overhead è lì, ma è piccolo , e raramente la pena preoccuparsi.)

E 'davvero difficile evitare il spazio del puntatore vtable, ma il puntatore stesso può essere ignorato, anche nel tuo esempio. Perché pFoo s 'inizializzazione è in tale ambito, il compilatore sa che pFoo->bar deve significare FooDerived :: bar , e non ha bisogno di controllare la vtable. Ci sono anche diverse tecniche di caching per evitare molteplici ricerche vtable, che vanno dal semplice al complesso.

Altri suggerimenti

Anche nel caso si mostra, dubito che qualsiasi compilatore farà quello che lei suggerisce.

Si utilizza un programma molto semplice tutto in un unico file.

Immaginate che avete dovuto FooBase e FooDerived in foo.h e Foo.cpp e principale in main.cpp. Quando si compila Foo.cpp, come è il compilatore a sapere che in tutto il programma non v'è alcuna necessità di un vtbl. E non ha visto main.cpp.

La determinazione finale può essere fatta solo in fase di collegamento, quando è troppo tardi e complicato per modificare il file oggetto, trovare tutte le chiamate a sizeof (FooDerived), ecc

Anche i più moderni, compilatori globalmente-ottimizzazione sono ancora attaccata al principio della "traduzione indipendente". Secondo questo principio, ogni unità di traduzione viene compilato in modo indipendente, senza alcuna conoscenza di eventuali altre unità di traduzione che potrebbero esistere in tutto il programma finale.

Quando si dichiara una classe con collegamento esterno, questa classe può essere utilizzato in altre unità di traduzione. Il compilatore non ha idea di come la classe potrebbe essere utilizzato in quelle altre unità di traduzione. Quindi, si deve supporre che ogni istanza di quella forza di classe in generale bisogno di suo puntatore tabella virtuale inizializzato correttamente al momento della costruzione.

Nel tuo esempio un compilatore intelligente potrebbe capire che il tipo di dinamica oggetto *pFoo è FooDerived. Ciò consentirebbe al compilatore di ottimizzare il codice: per generare una chiamata diretta a FooDerived::bar funzione in risposta a pFoo->bar() espressione (senza utilizzare la tabella virtuale). Ma tuttavia, il compilatore normalmente dovrebbe ancora inizializzare correttamente il puntatore del tavolo virtuale in ogni oggetto FooDerived.

E 'possibile per un compilatore per tagliare l'overhead indiretto di funzione virtuale chiamate quando si sa che il metodo di classe esatto sta per essere richiamato. Questo è il risultato di una forma di punti-a di analisi che compilatori ottimizzazione fanno. Ne tracciano il flusso di dati di variabili puntatore e ogni luogo un puntatore può puntare solo a oggetti di un tipo, può generare richieste di esattamente questo tipo, esecuzione semantica chiamata virtuali staticamente (cioè in fase di compilazione).

Come molti altri hanno detto, a meno che il compilatore sta facendo ottimizzazione dell'intero programma / link-tempo (diventando sempre più popolare; GCC guadagna in 4.5), ha ancora bisogno di generare una sorta di tabella di funzioni virtuali per supportare la compilazione separata .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top