2016-04-19 8 views
4

Angenommen, ich habe diese Hierarchie:Kompilierzeit Beseitigung von virtuellen Tabellen?

class Super 
{ 
public: 
    virtual void bar(); 
}; 

class Sub : public Super 
{ 
public: 
    virtual void bar() override; 
}; 

ist es eine Möglichkeit für mich vtables zu vermeiden, trotz des virtuellen Schlüsselwort verwenden? (Neugier) Ich habe etwas über eine Compiler-Optimierung lesen, die vtables eliminiert, wenn das Objekt während der Kompilierung bekannt ist, ich bin nicht wirklich sicher, für eine Weile um Google zu graben, aber could't keine Antworten finden, so bedeutet es, diese?

Sub sb; 
sb.bar(); //avoids vtable? 
Super& sr = sb; 
sr.bar(); //avoids vtable? 
Super* srp = &sb; 
srp->bar(); //avoids vtable? 
+3

Als ich den Zugriff über Vtable wissen, optimierter weg, wenn das Objekt zum Zeitpunkt der Kompilierung bekannt ist. Aber ich habe nie gesehen, dass die vtable selbst aus der Klasse entfernt wird, wenn sie nie benutzt wurde. Aber wenn Sie Ihren Code schreiben, dass Sie immer wissen, welches Objekt verwendet wird, entfernen Sie einfach das virtuelle :-) – Klaus

+0

Per Definition können die meisten Vtables zur Kompilierzeit nicht bekannt sein. Google späte Bindung. – Leandros

+0

Ja, die Frage ist etwas unklar: Wenn Sie sagen, „vermeiden vtables“, meinst du mit „Bypass eine bestehende VTable“ oder „vermeiden eine zu schaffen“? –

Antwort

6

Einer der gcc-Entwickler hat eine ganze series of blog posts about devirtualization. Ich denke, er ist auch aktiv in SO, also könnte es eine Chance geben, dass er reagiert.

jedoch devirtualization befasst sich hauptsächlich mit virtuellen Dispatch Beseitigung der durch den Programmablauf und mögliche Arten zu analysieren. Ich denke nicht, dass es die virtuelle Tabelle im Allgemeinen entfernt, aber es gibt ein Beispiel im zweiten Artikel, in dem ein virtuelles inlineed wird und dann vollständig zur Kompilierungszeit durch konstante Propagierung ausgewertet werden kann. In diesem Fall transformierte der Compiler/Linker das Programm, um die Klasse überhaupt nicht zu verwenden, und sollte daher kein Objekt oder keine Tabelle enthalten.

+0

Das ist eine nette Erklärung. Wenn die Funktionsquelle sichtbar ist, werden viele Optimierungen möglich, einschließlich der Inlinierung. –

2
Sub sb; 
sb.bar(); //avoids vtable? 

Die oben wird nie eine VTable für Versand, wie der Laufzeittyp bekannt ist (das heißt, es ist bekannt, dass sie die gleiche wie die Compile-Zeit/statischen Typ, nämlich Sub) verwenden müssen.

Super& sr = sb; 
sr.bar(); //avoids vtable? 


Super* srp = &sb; 
srp->bar(); //avoids vtable? 

In diesen Fällen, wenn die Zeiger/Referenz und Nutzung in der gleichen Funktion erscheinen, werden die Optimiser können auch intelligent genug, um Versand über eine V-Tabelle zu vermeiden. Wenn der Zeiger oder die Referenz an eine andere Out-of-Line-Funktion übergeben wird, die mit anderen Arten von Zeigern aufgerufen werden kann, wird normalerweise eine Vtable-basierte Verteilung benötigt.

Allgemeiner gesagt, der C++ Standard macht keine Vorgaben darüber, wie Laufzeit-Polymorphismus implementiert wird, daher gibt es keine garantierte, portable Möglichkeit, "vtables" zu eliminieren.

das gesagt ist, Ihre besten Wetten Nutzung des VTable für den Versand zu minimieren, sind:

  • überschreibt final zu markieren, wenn die Freiheit weiter außer Kraft setzen nicht tatsächlich erforderlich ist, und

  • zu halten die Implementierung inline (auch wenn implizit - durch die Funktionsimplementierung in der Klassendefinition)

Um zu sehen, ob ei Sie müssen experimentieren mit oder lesen Sie die Dokumente für Ihre eigenen Compiler/Tool-Kette, Optimierungsflags etc.

Eine unbenutzte VTable kann oder darf nicht vom Linker entfernt werden: Sie können wollen mit Cross Object Linker Optimierungsflags zu experimentieren, wenn Sie mehrere Übersetzungseinheiten haben.

Verwandte Themen