Sind reine Header-Bibliotheken effizienter?

48

Annahmen

  1. Einer der Vorteile von Nur-Header-Bibliotheken für C ++ besteht darin, dass sie nicht separat kompiliert werden müssen.

  2. In C und C ++ inlinemacht nur Sinn , wenn die Funktion definiert in einer Header - Datei *.

  3. 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

Vorac
quelle
2
Sie wären überrascht, wie gut viele moderne C ++ - Linker (GCC, MSVC, ICC usw.) Code in verschiedenen Übersetzungseinheiten einbinden können. In Bezug auf die Effizienz würde ich "generell nein" sagen, da die Häufigkeit, mit der Linker optimiert wurden, meinen Erwartungen widersprach und es trotzdem gelungen ist, Inline-Inhalte zu erstellen. . Bibliotheken, die nur Header enthalten und sowohl in der Benutzeroberfläche als auch in der Implementierung stabil sind, können jedoch aufgrund der einfachen Bereitstellung in neuen Projekten reizvoll sein.
1
Ich weiß nicht, dass dies eine vollständige Antwort verdient, aber ein großer Vorteil von nur Header-Bibliotheken ist die einfache Installation und Verwendung: Download, #include "lib.h (pp)", done.
WeRelic

Antworten:

44

Einer der Vorteile von Nur-Header-Bibliotheken für C ++ besteht darin, dass sie nicht separat kompiliert werden müssen

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.

In C und C ++ macht Inline nur Sinn, wenn die Funktion in einer Header-Datei definiert ist *

Dies hängt vom Compiler / Linker-System ab, aber ich denke, dass dies für die meisten vorhandenen C- und C ++ - Compiler zutrifft.

Traditionell wurde in C das Layout .c / .h verwendet, wobei der Header die minimale öffentliche Schnittstelle der Übersetzungseinheit darstellt. Ebenso .cpp / hpp.

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.

Doc Brown
quelle
6
Kurz gesagt: Nur-Header-Bibliotheken sind praktischer als effizienter . und da C ++ keinen standardmäßigen Paketmanager hat, hilft dies, die Akzeptanz voranzutreiben.
Matthieu M.
6
@MatthieuM: Nein, der kompilierte Code ist in der Tat manchmal effizienter, und für Template-Bibliotheken ist das reine Header-Design normalerweise keine Frage der Bequemlichkeit. Und längere Kompilierzeiten sind definitiv nicht bequemer.
Doc Brown
Das Vorhandensein des Hot-Codes in den Headern kann zwar zu einem effizienteren kompilierten Code führen, dies erfordert jedoch nicht, dass der gesamte Code in den Headern enthalten ist, und ist daher, meiner Meinung nach, unabhängig von reinen Header-Bibliotheken.
Matthieu M.
1
@MatthieuM .: das ist sicher richtig, trotzdem finde ich den begriff "bequemer" beschreibt den fall nicht gut.
Doc Brown
3
Ich habe an einem großen Embedded-Projekt auf einem abgespeckten, älteren Betriebssystem für meinen früheren Arbeitgeber gearbeitet, und in diesen Fällen kann ich den Schmerz langer Kompilierzeiten bezeugen. Jeder, der erwischt wird, wie er zu viel in Header-Dateien steckt, wird gnadenlos behandelt.
Fred Thomsen
15

Nun, lassen Sie uns zuerst einige Ihrer Annahmen demolieren:

  1. Einer der Vorteile von Nur-Header-Bibliotheken für C ++ besteht darin, dass sie nicht separat kompiliert werden müssen.

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.

  1. In C und C ++ macht Inline nur Sinn, wenn die Funktion in einer Header-Datei * definiert ist.

Ja, der einzige Effekt inlineist 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.

  1. Traditionell wurde in C das Layout .c / .h verwendet, wobei der Header die minimale öffentliche Schnittstelle der Übersetzungseinheit darstellt. Ebenso .cpp / hpp.

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.

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?

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.

Deduplizierer
quelle