Wenn ich eine Klasse wie folgt definiere:
%Vor% Bedeutet dies, dass der virtuelle Destruktor und func
inline sind
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:
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.
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
print(d)
by d.foo()
nicht ersetzen und den Aufruf nicht devirtualisieren 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.
Tags und Links class c++ inline virtual-destructor