Annahmen
Einer der Vorteile von Nur-Header-Bibliotheken für C ++ besteht darin, dass sie nicht separat kompiliert werden müssen.
In C und C ++
inline
macht nur Sinn , wenn die Funktion definiert in einer Header - Datei *.Traditionell wurde in C das Layout .c / .h verwendet, wobei der Header die minimale öffentliche Schnittstelle der Übersetzungseinheit darstellt. Ebenso .cpp / hpp.
Frage
Sind reine Header-Bibliotheken im Allgemeinen in Bezug auf Code und Ausführungszeit effizienter als das herkömmliche Layout? Wenn ja, liegt dies an umfangreichen Inlining- oder anderen Optimierungen?
* - Das Definieren der Funktion in einem Header ermöglicht es dem Compiler, die Implementierung während des Kompilierens einer Übersetzungseinheit zu sehen, und ermöglicht praktisch Inlining-Code
Antworten:
Nein, das ist kein Vorteil, ganz im Gegenteil - der Hauptteil der Bibliothek muss so oft wie möglich kompiliert werden, nicht nur einmal. Das erhöht normalerweise die Kompilierzeiten. Wenn Sie sich jedoch auf die Vorteile beziehen, die hier in Wikipedia aufgeführt sind : In diesem Artikel geht es um einen geringeren Verwaltungsaufwand für den gesamten Erstellungs-, Verpackungs- und Bereitstellungsprozess.
Dies hängt vom Compiler / Linker-System ab, aber ich denke, dass dies für die meisten vorhandenen C- und C ++ - Compiler zutrifft.
Das ist meistens richtig. C ++ - Klassenheader enthalten häufig mehr als die minimale öffentliche Schnittstelle - sie enthalten normalerweise auch viel privates Material. Um dies zu mildern, werden Dinge wie das PIMPL-Idiom verwendet. Dies ist so etwas wie das "Gegenteil" einer reinen Header-Bibliothek. Sie versucht, den erforderlichen Header-Inhalt zu minimieren.
Aber um Ihre Hauptfrage zu beantworten: Dies ist ein Kompromiss. Je mehr Bibliothekscode man in die Header-Dateien einfügt, desto mehr hat der Compiler die Möglichkeit, den Code hinsichtlich der Geschwindigkeit zu optimieren (ob dies wirklich geschieht oder ob die Erhöhung bemerkenswert ist, ist eine ganz andere Frage). Andererseits erhöht zu viel Code in den Kopfzeilen die Kompilierzeit. Besonders in großen C ++ - Projekten kann dies zu einem ernsthaften Problem werden, siehe "Large Scale C ++ Software Design" von John Lakos - obwohl das Buch ein wenig veraltet ist und einige der dort beschriebenen Probleme von modernen Compilern angesprochen werden. Lösungen sind noch gültig.
Insbesondere wenn Sie keine stabile Bibliothek (von Drittanbietern) verwenden, aber während Ihres Projekts Ihre eigenen Bibliotheken entwickeln, werden die Kompilierungszeiten deutlich. Jedes Mal, wenn Sie etwas in der Bibliothek ändern, müssen Sie eine Header-Datei ändern, wodurch alle abhängigen Units neu kompiliert und verknüpft werden.
IMHO wird die Popularität von Nur-Header-Bibliotheken durch die Popularität der Template-Metaprogrammierung verursacht. Für die meisten Compiler, als Templat libs muss Kopf nur sein , weil der Compiler nur die Haupt-Kompilierung starten kann , wenn die Parameter des Typs vorgesehen sind, und für die vollständige Erfassung und Optimierung der Compiler muss „beide auf einmal“ sehen - die Bibliothek Code sowie die Vorlage Parameterwerte. Das macht es unmöglich (oder zumindest schwierig), "vorkompilierte" Kompilierungseinheiten für eine solche Bibliothek zu erstellen.
quelle
Nun, lassen Sie uns zuerst einige Ihrer Annahmen demolieren:
Wenn Sie Dinge separat kompilieren, müssen Sie möglicherweise nicht alles neu kompilieren, wenn sich nur ein Teil ändert.
Also ein Nachteil statt eines Vorteils.
Ja, der einzige Effekt
inline
ist die Ausnahme von der Ein-Definition-Regel .Wehe dir, wenn diese Definitionen in irgendeiner Weise unterschiedlich sind.
Wenn also eine Funktion in einer Kompilierungseinheit enthalten ist, markieren Sie sie
static
. Dies erhöht auch die Wahrscheinlichkeit von Inlining, da die Funktion verfügbar sein muss, um es zu inlineen.Schauen Sie sich dennoch die Link-Time-Optimierung an, die mindestens von MSVC ++, gcc und clang unterstützt wird.
Nun, nur die minimale Oberfläche zu präsentieren, ist sicherlich eines der Ziele, eine höhere API- und ABI-Stabilität zu erreichen und die Kompilierungszeiten zu minimieren.
Insbesondere C ++ - Klassen sind jedoch nicht wirklich darauf ausgerichtet, da alle privaten Bits in den Header gelangen, ebenso wie die geschützten, ob Sie davon abgeleitet werden möchten oder nicht.
Das Entwurfsmuster PIMPL dient zum Reduzieren solcher Details.
Der Teil, bei dem die Trennung von Schnittstelle und Implementierung in C ++ völlig fehlschlägt, sind jedoch Vorlagen.
Das Komitee hat versucht, etwas mit exportierten Vorlagen zu tun , aber das wurde als zu kompliziert und nicht wirklich funktionierend aufgegeben.
Jetzt arbeiten sie an einem richtigen Modulsystem , obwohl es nur langsam geht. Das verkürzt die Kompilierungszeiten erheblich und sollte auch die API- und ABI-Stabilität erhöhen, indem die Oberfläche verringert wird.
Nur-Header-Bibliotheken können effizienter in Bezug auf Codegröße und Ausführungszeit sein. Dies hängt jedoch davon ab, ob die Bibliothek gemeinsam genutzt wird, wie viel davon verwendet wird, auf welche Weise und ob Inlining in diesem speziellen Fall einen entscheidenden Gewinn darstellt.
Und der Grund, warum Inlining für die Optimierung so wichtig ist, ist nicht, dass Inlining selbst einen so großen Schub darstellt, sondern dass es sich aufgrund der Möglichkeiten zur ständigen Weitergabe und weiteren Optimierung öffnet.
quelle