Können virtuelle Funktionen inline sein [duplizieren]

8

Wenn ich eine Klasse wie folgt definiere:

%Vor%

Bedeutet dies, dass der virtuelle Destruktor und func inline sind

    
Ghostblade 25.08.2013, 18:04
quelle

2 Antworten

10

Ob der Compiler entscheidet, eine Funktion, die inline definiert ist, zu inline zu schreiben, hängt vollständig vom Compiler ab. Im Allgemeinen können virtual -Funktionen nur inlined sein, wenn der Compiler entweder beweisen kann, dass der statische Typ dem dynamischen Typ entspricht oder wenn der Compiler den dynamischen Typ sicher bestimmen kann. Wenn Sie z. B. einen Wert vom Typ A verwenden, weiß der Compiler, dass der dynamische Typ nicht unterschiedlich sein kann und die Funktion inline sein kann. Bei Verwendung eines Zeigers oder einer Referenz kann der Compiler im Allgemeinen nicht beweisen, dass der statische Typ derselbe ist, und virtual -Funktionen müssen im Allgemeinen dem üblichen virtuellen Dispatch folgen. Aber selbst wenn ein Zeiger verwendet wird, kann der Compiler genügend Informationen aus dem Kontext haben, um den genauen dynamischen Typ zu kennen. Zum Beispiel, MatthieuM. gab folgendes Beispiel:

%Vor%

In diesem Fall kann der Compiler feststellen, dass a auf ein B -Objekt zeigt und somit die korrekte Version von func() ohne dynamischen Versand aufruft. Ohne den dynamischen Versand könnte func() dann inline sein. Ob Compiler die entsprechende Analyse durchführen, hängt natürlich von der jeweiligen Implementierung ab.

Wie der hdv richtig ausgeführt hat, kann der virtuelle Versand umgangen werden, indem eine virtuelle Funktion mit voller Qualifikation aufgerufen wird, z. B. a->A::func() , in welchem ​​Fall die virtuelle Funktion auch inline sein kann. Der Hauptgrund, warum virtuelle Funktionen im Allgemeinen nicht inline sind, ist die Notwendigkeit eines virtuellen Versands. Mit der vollen Qualifikation ist jedoch die anzurufende Funktion bekannt.

    
Dietmar Kühl 25.08.2013, 18:06
quelle
4

Ja und auf verschiedene Arten. Sie können einige Beispiele für Devirtualisierung in dieser E-Mail

Wie bei allen Optimierungen stehen die Möglichkeiten des Compilers zur Eliminierung von Alternativen aus: Wenn er beweisen kann, dass der virtuelle Aufruf immer in Derived::func aufgelöst wird, kann er ihn direkt aufrufen.

Es gibt verschiedene Situationen, beginnen wir zuerst mit den semantischen Beweisen:

  • SomeDerived& d wobei SomeDerived ist final erlaubt die Devirtualisierung aller Methodenaufrufe
  • SomeDerived& d , d.foo() wobei foo ist final erlaubt auch die Devirtualisierung dieses bestimmten Aufrufs

Dann gibt es Situationen, in denen Sie den dynamischen Typ des Objekts kennen:

  • SomeDerived d; = & gt; Der dynamische Typ von d ist notwendigerweise SomeDerived
  • SomeDerived d; Base& b; = & gt; Der dynamische Typ von b ist notwendigerweise SomeDerived

Diese 4 Devirtualisierungssituationen werden normalerweise vom Compiler-Frontend gelöst, da sie grundlegendes Wissen über die Sprachsemantik benötigen. Ich kann bestätigen, dass alle 4 in Clang implementiert sind und ich denke, dass sie auch in gcc implementiert sind.

Es gibt jedoch viele Situationen, in denen dies zusammenbricht:

%Vor%

Auch wenn hier offensichtlich ist, dass der Aufruf von foo in Derived::foo aufgelöst wird, wird Clang / LLVM ihn nicht optimieren. Das Problem ist, dass

  • Clang (Front-End) führt kein Inlining durch, daher kann es print(d) by d.foo() nicht ersetzen und den Aufruf nicht devirtualisieren
  • LLVM (Back-End) kennt die Semantik der Sprache nicht, daher wird selbst nach dem Ersetzen von print(d) durch d.foo() angenommen, dass der virtuelle Zeiger von d durch opaque (dessen Definition) hätte geändert werden können ist undurchsichtig, wie der Name schon sagt)

Ich habe die Bemühungen auf der Mailingliste von Clang und LLVM verfolgt, da beide Gruppen von Entwicklern über den Verlust von Informationen nachgedacht haben und wie man Clang dazu bringt, LLVM zu sagen: "Es ist in Ordnung", aber leider ist das Problem nicht trivial noch nicht gelöst ... also die halbherzige Devirtualisierung im Front-End, um alle offensichtlichen und einige nicht so offensichtliche Fälle zu untersuchen (obwohl das Front-End-System konventionell nicht implementiert ist).

Als Referenz finden Sie den Code für die Devirtualisierung in Clang in CGExprCXX.cpp in einer Funktion namens %Code%. Es ist nur ~ 64 Zeilen lang (gerade jetzt) ​​und gründlich kommentiert.

    
Matthieu M. 25.08.2013 18:44
quelle