Wie hoch sind die Kosten für den Aufruf einer virtuellen Funktion auf nicht-polymorphe Weise?

8

Ich habe eine reine abstrakte Basis und zwei abgeleitete Klassen:

%Vor%

Ist das Aufrufen von foo in Punkt A genauso teuer wie der Aufruf einer nicht virtuellen Memberfunktion? Oder ist es teurer als wenn D1 und D2 nicht von B abgeleitet wären?

%Vor%

Antwort: Die Antwort von Andy Prowl ist die richtige Antwort, ich wollte nur die Assembly-Ausgabe von gcc hinzufügen (getestet in godbolt : gcc-4.7 -O2 -march = nativ -std = c ++ 11). Die Kosten der direkten Funktionsaufrufe sind:

%Vor%

Und für die polymorphen Aufrufe:

%Vor%

Wenn die Objekte jedoch nicht von B abgeleitet sind und Sie nur den direkten Aufruf ausführen, wird gcc inline die Funktion aufrufen:

%Vor%

Dies könnte weitere Optimierungen ermöglichen, wenn D1 und D2 nicht von B herrühren, also denke ich, dass no, sie sind nicht äquivalent (at zumindest für diese Version von gcc mit diesen Optimierungen erzeugte -O3 eine ähnliche Ausgabe ohne Inlining. Gibt es etwas, das die Einbindung des Compilers verhindert, wenn D1 und D2 von B abgeleitet werden?

"Fix": Verwenden Sie Delegaten (auch virtuelle Funktionen neu implementiert):

%Vor%

und dann einen Vektor von Delegierten erstellen:

%Vor%

Dies ermöglicht Inlining, wenn Sie auf die Methoden nicht-polymorph zugreifen. Ich schätze jedoch, dass der Zugriff auf den Vektor langsamer ist (oder zumindest so schnell, weil std::function virtuelle Funktionen zum Löschen von Typen verwendet) als nur virtuelle Funktionen zu verwenden (kann noch nicht mit godbolt testen).

    
gnzlbg 17.02.2013, 15:48
quelle

2 Antworten

8
  

Kostet das Aufrufen von foo in Point A genauso viel wie ein Aufruf einer nicht virtuellen Member-Funktion?

Ja.

  

Oder ist es teurer als wenn D1 und D2 nicht von B abgeleitet wären?

Nein.

Der Compiler löst diese Funktionsaufrufe statisch auf, weil sie nicht durch einen Zeiger oder durch einen Verweis ausgeführt werden. Da der Typ der Objekte, auf denen die Funktion aufgerufen wird, zur Kompilierungszeit bekannt ist, weiß der Compiler, welche Implementierung von foo() aufgerufen werden muss.

    
Andy Prowl 17.02.2013, 15:54
quelle
4

Die einfachste Lösung sieht sich die Compiler-Innereien an. In Clang finden wir canDevirtualizeMemberFunctionCall in lib / CodeGen / CGClass.cpp :

%Vor%

Ich glaube, dass der Code (und die zugehörigen Kommentare) selbsterklärend sind:)

    
Matthieu M. 17.02.2013 16:58
quelle