Fügt die Verwendung von specifier final
in class
oder in function
Speicher- oder CPU-Overhead hinzu oder wird sie nur zur Kompilierzeit verwendet?
Und wie erkennt std::is_final
, was endgültig ist?
Es kann tatsächlich den Overhead reduzieren. Und in seltenen Fällen, erhöhen Sie es.
Wenn Sie einen Zeiger auf eine final
class A
haben, können alle virtuellen Methodenaufrufe de-virtualisiert und direkt aufgerufen werden. Ebenso kann ein Aufruf einer virtuellen Methode final
de-virtualisiert werden. Darüber hinaus ist der Vererbungsbaum einer final
-Klasse fest, selbst wenn er virtual
Elternklassen enthält, so dass Sie einige Eltern-Zugriffe de-virtualisieren können.
Jede dieser De-Virtualisierungen reduziert oder eliminiert die Anforderung, dass eine Laufzeitstruktur (die vtable) abgefragt werden muss.
Es kann einen leichten Nachteil geben. Einige Codiertechniken beruhen auf dem vtable-Zugriff, um den direkten Zugriff auf ein Symbol zu vermeiden, und exportieren das Symbol dann nicht. Der Zugriff auf eine vtable kann über Konvention erfolgen (ohne Symbole aus einer Bibliothek, nur die Header-Datei für die fraglichen Klassen), während der Zugriff auf eine Methode direkt eine Verknüpfung mit diesem Symbol erfordert.
Dies bricht eine Form der dynamischen C ++ - Bibliotheksverknüpfung (wobei Sie vermeiden, mehr als ein dll-Ladesymbol und / oder C-Verknüpfungsfunktionen, die Zeiger zurückgeben, zu verknüpfen, und Klassen werden über ihre VTables exportiert).
Es ist auch möglich, dass wenn Sie eine Verknüpfung mit einem Symbol in einer dynamischen Bibliothek herstellen, das Laden des dynamischen Bibliothekssymbols teurer sein könnte als das Suchen mit vtable. Ich habe das nicht erlebt oder profiliert, aber ich habe es gesehen. Die Vorteile sollten diese Kosten im Allgemeinen überwiegen. Alle diese Kosten stellen eine Qualität der Implementierung dar, da die Kosten nicht auftreten müssen, weil die Methode final
ist.
Schließlich verhindert final
den Trick der leeren Basisoptimierung bei Klassen, wo jemand weiß, dass Ihre Klasse keinen Status hat, und erbt von ihr, um den Aufwand beim "Speichern" einer Instanz Ihrer Klasse von 1 Byte auf 0 Byte zu reduzieren. Wenn Ihre Klasse leer ist und keine virtuellen Methoden / Vererbung enthält, verwenden Sie nicht final
, um zu verhindern, dass diese Klasse blockiert wird. Es gibt keine Entsprechung für final
-Funktionen.
Abgesehen von dem Problem der EBO-Optimierung (das nur bei leeren Typen auftritt), kommt jeder Overhead von final
daher, wie anderer Code damit interagiert, und wird selten sein. Weitaus häufiger wird es anderen Code schneller machen, da die direkte Interaktion mit einer Methode einen direkteren Aufruf der Methode ermöglicht und zu Anklopfoptimierungen führen kann (weil der Aufruf vom Compiler besser verstanden werden kann). p>
Das Markieren von irgendetwas außer einem leeren Typ als final
, wenn es endgültig ist, ist zur Laufzeit harmlos. Dies kann bei Klassen mit virtuellen Funktionen und Vererbung zur Laufzeit vorteilhaft sein.
std::is_final
und ähnliche Merkmale werden fast alle über die eingebaute Magie des Compilers implementiert. Eine gute Anzahl der Eigenschaften in std
benötigt eine solche Magie. Siehe Wie erkennt man, ob eine Klasse in C ++ 11 final ist? (Danke an @Csq für das Finden)
Nein, es wird nur zur Kompilierzeit verwendet
Magie ( siehe hier für weitere Informationen - danke Csq für den Link)