Gibt es Auswirkungen auf die Leistung, wenn jeder Header eingeschlossen wird?
Lesezeit: 6 Minuten
Martin Heralecký
Nehmen wir an, ich möchte verwenden hex() Funktion. Ich weiß, dass es in definiert ist <ios> Header und ich weiß auch, dass es darin enthalten ist <iostream> Header. Der Unterschied liegt darin <iostream> sind viel mehr Funktionen und andere Dinge, die ich nicht brauche.
Sollte es mir aus Performance-Sicht wichtig sein, weniger Funktionen, Klassen usw. einzubeziehen/zu definieren als mehr?
Es wirkt sich auf die Größe Ihrer Binärdatei aus, aber ich denke, es wird keine Leistungsprobleme geben.
– Haris
13. November 2015 um 17:09 Uhr
@Haris: nein, das stimmt im allgemeinen Fall nicht.
– PaulR
13. November 2015 um 17:12 Uhr
@PaulR, wird es Leistungsprobleme geben?
– Haris
13. November 2015 um 17:14 Uhr
@Haris es wird wahrscheinlich, wenn überhaupt, nur sehr geringe Auswirkungen auf die Größe der Binärdatei haben. Wenn Prototypen und Deklarationen aus dem Header beim Kompilieren vorhanden sind, wird der zugehörige ausführbare Code nicht automatisch hinzugefügt (es sei denn, er wird verwendet, dann wird er während des Verknüpfens hinzugefügt), und beim dynamischen Verknüpfen wäre dieser Code eher Teil der verknüpften Bibliotheken als der ausführbaren Datei ohnehin.
– Dimitri
13. November 2015 um 17:14 Uhr
@Haris: nein, ich meinte, dass es im Allgemeinen keinen Einfluss auf die Größe der resultierenden Binärdatei hat, wie Sie behaupten.
– PaulR
13. November 2015 um 17:15 Uhr
Wenn der Standard sagt, dass es im Header definiert ist <ios> dann Header einfügen <ios> da Sie nicht garantieren können, dass es in/durch einen anderen Header eingefügt wird.
Dies ist im Allgemeinen falsch, weil Sie kann Verlassen Sie sich auf einige zu definierende Symbole, wenn ein anderer Header enthalten ist; Erwägen std::begin.
– edmz
13. November 2015 um 19:06 Uhr
Widerspricht irgendetwas in der Frage dieser Notwendigkeit oder stellt sie in Frage?
– Deduplizierer
13. November 2015 um 19:24 Uhr
@black – Sie können sich darauf verlassen, dass Symbole in der Kopfzeile oder den Kopfzeilen definiert sind, in denen der Standard sagt, dass sie definiert sind. Sehr wenige müssen in mehr als einem Header vorhanden sein. Die meisten Implementierungen definieren am Ende einige Symbole in mehr als einem Header, weil sie intern benötigt werden, aber das ist implementierungsspezifisch, dh nichts, worauf Sie sich verlassen können.
– Peter Becker
13. November 2015 um 21:11 Uhr
Anon Mail
Es gibt keinen Leistungseinbruch zur Laufzeit.
Es könnte jedoch zu einer übermäßigen Kompilierzeit kommen, wenn Tonnen von unnötigen Headern enthalten sind.
Wenn dies erledigt ist, können Sie auch unnötige Neukompilierungen erstellen, wenn beispielsweise ein Header geändert wird, aber eine Datei, die ihn nicht verwendet, ihn enthält.
In kleinen Projekten (mit kleinen Headern) spielt dies keine Rolle. Wenn ein Projekt wächst, kann es sein.
Es ist möglich, durch statische Initialisierung von Variablen in einem Header etwas Laufzeit-Overhead hinzuzufügen.
– Praxeolit
17. November 2015 um 11:16 Uhr
Du hast Recht. Aber ich denke, dass Variablen in Headern entweder versehentlich oder selten für fortgeschrittene Zwecke verwendet werden.
– Anon Mail
17. November 2015 um 17:40 Uhr
Deduplikator
TL;DR: Im Allgemeinen ist es besser, nur das aufzunehmen, was Sie brauchen. Darunter mehr kann wirken sich nachteilig auf die Binärgröße und den Start aus (sollte unbedeutend sein), beeinträchtigen jedoch meistens die Kompilierungszeit ohne vorkompilierte Header.
Nun, natürlich müssen Sie mindestens diese Header zusammenfügen, die garantiert alle Ihre Verwendungen abdecken.
Es kann vorkommen, dass es trotzdem “funktioniert”, da die Standard-C++-Header alle einander nach Wunsch des Implementierers enthalten dürfen und die Header zusätzliche Symbole in der enthalten dürfen std-namespace sowieso (siehe Warum wird die Verwendung von Namespace std als schlechte Praxis angesehen?).
Als nächstes kann das Einfügen eines zusätzlichen Headers manchmal zur Erstellung zusätzlicher Objekte führen (siehe std::ios_base::Init), obwohl eine gut gestaltete Bibliothek solche minimiert (das ist meines Wissens die einzige Instanz in der Standardbibliothek).
Aber das große Problem ist eigentlich nicht die Größe und Effizienz der kompilierten (und optimierten) Binärdatei (die unberührt bleiben sollte, abgesehen vom vorherigen Punkt, dessen Effekt minimal sein sollte), sondern die Kompilierungszeit während der aktiven Entwicklung (siehe auch How does #include funktioniert in C++?).
Und letzteres wird (schwer, so sehr, dass das Komitee an einem Modulvorschlag arbeitet, siehe C++-Module – warum wurden sie aus C++0x entfernt? Werden sie später wiederkommen?) durch das Hinzufügen überflüssiger Header negativ beeinflusst.
Es sei denn natürlich, Sie verwenden vorkompilierte Header (siehe Warum vorkompilierte Header verwenden (C/C++)?). In diesem Fall fügen Sie mehr in die vorkompilierten Header ein und damit überall statt nur dort, wo sie benötigt werden, solange diese Header nicht geändert werden , wird die Kompilierzeit tatsächlich die meiste Zeit verkürzen.
Es gibt ein Clang-basiertes Tool zum Ermitteln der minimalen Header namens schließen Sie ein, was Sie verwenden.
Es analysiert den Klang AST, um das zu entscheiden, was sowohl eine Stärke als auch eine Schwäche ist:
Sie müssen ihm nicht alle Symbole beibringen, die ein Header zur Verfügung stellt, aber er weiß auch nicht, ob es in dieser Überarbeitung gerade so geklappt hat oder ob sie vertraglich vereinbart sind.
Sie müssen also die Ergebnisse überprüfen.
Das Einfügen unnötiger Header hat folgende Nachteile.
Längere Kompilierzeit, Linker muss alle ungenutzten Symbole entfernen.
Wenn Sie in CPP zusätzliche Header hinzugefügt haben, wirkt sich dies nur auf Ihren Code aus.
Aber wenn Sie Ihren Code als Bibliothek verteilen und unnötige Header in Ihren Header-Dateien hinzugefügt haben. Der Clientcode wird damit belastet, die von Ihnen verwendeten Header zu finden.
Vertrauen Sie nicht der indirekten Einbeziehung, verwenden Sie den Header, in dem die erforderliche Funktion tatsächlich definiert ist.
Auch in einem Projekt sollten Header als gute Programmierpraxis enthalten sein, um Abhängigkeiten zu reduzieren.
//local header -- most dependent on other headers
#include <project/impl.hpp>
//Third party library headers -- moderately dependent on other headers
#include <boost/optional.hpp>
//standard C++ header -- least dependent on other header
#include <string>
Und Dinge, die nicht betroffen sind, sind die Laufzeit, der Linker entfernt nicht verwendete Symbole während der Kompilierung.
Einschließlich nicht benötigter Header-Dateien hat etwas Wert.
Es erfordert weniger Codierungsaufwand, um das normalerweise benötigte Ausschneiden und Einfügen einzufügen includes. Natürlich ist die spätere Codierung jetzt damit belastet, nicht zu wissen, was wirklich benötigt wurde.
Insbesondere in C mit seiner eingeschränkten Namensraumkontrolle werden Kollisionen einschließlich unnötiger Header sofort erkannt. Sprich Code definiert eine globale Nicht-static Variable oder Funktion, die zufällig dem Standard entsprach, wie z erfc() etwas Textverarbeitung zu tun. Durch Einbeziehung <math.h>mit wird die Kollision erkannt double erfc(double x)obwohl dies .c Datei macht keine FP-Mathematik noch andere .c Dateien tun.
#include <math.h>
char *erfc(char *a, char *b);
OTOH, hatte dies .c Datei nicht enthalten <math.h>, zur Verbindungszeit würde die Kollision erkannt werden. Die Auswirkungen dieser verspäteten Benachrichtigung könnten groß sein, wenn die Codebasis jahrelang keine FP-Mathematik benötigt hätte und dies jetzt tut, nur um sie zu erkennen char *erfc(char *a, char *b) an vielen Orten verwendet.
IMO: Bemühen Sie sich angemessen, unnötige Header-Dateien nicht einzufügen, aber machen Sie sich keine Sorgen, ein paar zusätzliche einzufügen, insbesondere wenn es sich um häufige handelt. Wenn eine automatisierte Methode vorhanden ist, verwenden Sie sie, um die Aufnahme von Header-Dateien zu steuern.
11452400cookie-checkGibt es Auswirkungen auf die Leistung, wenn jeder Header eingeschlossen wird?yes
Es wirkt sich auf die Größe Ihrer Binärdatei aus, aber ich denke, es wird keine Leistungsprobleme geben.
– Haris
13. November 2015 um 17:09 Uhr
@Haris: nein, das stimmt im allgemeinen Fall nicht.
– PaulR
13. November 2015 um 17:12 Uhr
@PaulR, wird es Leistungsprobleme geben?
– Haris
13. November 2015 um 17:14 Uhr
@Haris es wird wahrscheinlich, wenn überhaupt, nur sehr geringe Auswirkungen auf die Größe der Binärdatei haben. Wenn Prototypen und Deklarationen aus dem Header beim Kompilieren vorhanden sind, wird der zugehörige ausführbare Code nicht automatisch hinzugefügt (es sei denn, er wird verwendet, dann wird er während des Verknüpfens hinzugefügt), und beim dynamischen Verknüpfen wäre dieser Code eher Teil der verknüpften Bibliotheken als der ausführbaren Datei ohnehin.
– Dimitri
13. November 2015 um 17:14 Uhr
@Haris: nein, ich meinte, dass es im Allgemeinen keinen Einfluss auf die Größe der resultierenden Binärdatei hat, wie Sie behaupten.
– PaulR
13. November 2015 um 17:15 Uhr