In welcher Reihenfolge sollten Dateien angegeben werden, dh aus welchen Gründen wird ein Header vor einem anderen eingefügt?
Gehen die Systemdateien STL und Boost beispielsweise vor oder nach den lokalen Include-Dateien?
In welcher Reihenfolge sollten Dateien angegeben werden, dh aus welchen Gründen wird ein Header vor einem anderen eingefügt?
Gehen die Systemdateien STL und Boost beispielsweise vor oder nach den lokalen Include-Dateien?
Antworten:
Ich glaube nicht, dass es eine empfohlene Bestellung gibt, solange sie kompiliert wird! Was ärgerlich ist, ist, wenn einige Header erfordern, dass andere Header zuerst eingeschlossen werden ... Das ist ein Problem mit den Headern selbst, nicht mit der Reihenfolge der Includes.
Meine persönliche Präferenz ist es, von lokal zu global zu wechseln, wobei jeder Unterabschnitt in alphabetischer Reihenfolge angezeigt wird, dh:
Meine Begründung für 1. ist, dass es beweisen sollte, dass jeder Header (für den es einen CPP gibt) #include
ohne Voraussetzungen d sein kann (terminus technicus: Header ist "in sich geschlossen"). Und der Rest scheint nur logisch von dort zu fließen.
Das Wichtigste ist, dass Ihre Header nicht davon abhängig sein sollten, dass zuerst andere Header eingefügt werden. Eine Möglichkeit, dies sicherzustellen, besteht darin, Ihre Header vor allen anderen Headern einzuschließen.
Insbesondere "Thinking in C ++" erwähnt dies und verweist auf Lakos '"Large Scale C ++ Software Design":
Latente Verwendungsfehler können vermieden werden, indem sichergestellt wird, dass die .h-Datei einer Komponente von selbst analysiert wird - ohne extern bereitgestellte Deklarationen oder Definitionen ... Wenn Sie die .h-Datei als allererste Zeile der .c-Datei einschließen, wird sichergestellt, dass kein kritisches Element vorhanden ist In der .h-Datei fehlen Informationen, die der physischen Schnittstelle der Komponente eigen sind (oder, falls vorhanden, Sie werden davon erfahren, sobald Sie versuchen, die .c-Datei zu kompilieren).
Das heißt, in der folgenden Reihenfolge einschließen:
Wenn einer der Header ein Problem mit der Aufnahme in diese Reihenfolge hat, beheben Sie ihn entweder (falls vorhanden) oder verwenden Sie ihn nicht. Boykottieren Sie Bibliotheken, die keine sauberen Header schreiben.
Googles C ++ - Styleguide argumentiert fast umgekehrt, ohne wirklich zu rechtfertigen. Ich persönlich tendiere dazu, den Lakos-Ansatz zu bevorzugen.
Ich folge zwei einfachen Regeln, die die überwiegende Mehrheit der Probleme vermeiden:
Ich folge auch den Richtlinien von:
Mit anderen Worten:
#include <stdio.h>
#include <string.h>
#include "btree.h"
#include "collect_hash.h"
#include "collect_arraylist.h"
#include "globals.h"
Als Richtlinien ist das allerdings eine subjektive Sache. Auf der anderen Seite setze ich die Regeln strikt durch, bis ich Wrapper-Header-Dateien mit Include-Guards und gruppierten Includes versorge, wenn ein widerlicher Entwickler von Drittanbietern meine Vision nicht abonniert :-)
Um meinen eigenen Ziegelstein an die Wand zu hängen.
Also gehe ich normalerweise so:
// myproject/src/example.cpp
#include "myproject/example.h"
#include <algorithm>
#include <set>
#include <vector>
#include <3rdparty/foo.h>
#include <3rdparty/bar.h>
#include "myproject/another.h"
#include "myproject/specific/bla.h"
#include "detail/impl.h"
Jede Gruppe durch eine Leerzeile von der nächsten getrennt:
Beachten Sie außerdem, dass sich jede Datei, abgesehen von den Systemheadern, in einem Ordner mit dem Namen ihres Namespace befindet, nur weil es einfacher ist, sie auf diese Weise aufzuspüren.
#define
, wenn es darum geht , anderen Code durcheinander zu bringen) als auch um implizite Abhängigkeiten zu vermeiden. Wenn zum Beispiel unsere Codebasis-Header-Datei foo.h
wirklich davon abhängt, <map>
aber überall dort, wo sie in .cc
Dateien verwendet wurde, <map>
zufällig bereits enthalten war, würden wir es wahrscheinlich nicht bemerken. Bis jemand versuchte einzuschließen, foo.h
ohne vorher einzuschließen <map>
. Und dann würden sie sich ärgern.
.h
mindestens eines enthält .cpp
, das es zuerst enthält (in meinem persönlichen Code enthält der zugehörige Komponententest es zuerst und der Quellcode enthält es in seiner rechtmäßigen Gruppe ). Wenn einer der Header nicht beeinflusst wird, werden <map>
alle nachfolgend enthaltenen Header ohnehin beeinflusst, so dass es für mich ein verlorener Kampf ist.
Header corresponding to this cpp file first (sanity check)
. H. Gibt es etwas Besonderes, wenn #include "myproject/example.h"
es an das Ende aller Includes verschoben wird?
Ich empfehle:
Und natürlich, wenn möglich, in alphabetischer Reihenfolge in jedem Abschnitt.
Verwenden Sie immer Forward-Deklarationen, um unnötige #include
s in Ihren Header-Dateien zu vermeiden .
Ich bin mir ziemlich sicher, dass dies nirgendwo in der vernünftigen Welt eine empfohlene Vorgehensweise ist, aber ich mag es, System-Includes nach Dateinamenlänge zu ordnen, die lexikalisch innerhalb derselben Länge sortiert sind. Wie so:
#include <set>
#include <vector>
#include <algorithm>
#include <functional>
Ich denke, es ist eine gute Idee, eigene Header vor anderen Völkern einzufügen, um die Schande der Abhängigkeit von der Reihenfolge der Einschlüsse zu vermeiden.
windows.h
.
Das ist nicht subjektiv. Stellen Sie sicher, dass Ihre Header nicht darauf angewiesen sind, #include
in einer bestimmten Reihenfolge d zu sein. Sie können sicher sein, dass es keine Rolle spielt, in welcher Reihenfolge Sie STL- oder Boost-Header einfügen.
Fügen Sie zuerst den Header ein, der der .cpp entspricht. Mit anderen Worten, source1.cpp
sollte enthalten sein, source1.h
bevor Sie etwas anderes einfügen . Die einzige Ausnahme, an die ich denken kann, ist die Verwendung von MSVC mit vorkompilierten Headern. In diesem Fall müssen Sie stdafx.h
vor allem anderen einschließen .
Begründung: Durch das Einfügen der source1.h
vorherigen Dateien wird sichergestellt, dass sie ohne Abhängigkeiten eigenständig sind. Wenn Sie source1.h
zu einem späteren Zeitpunkt eine Abhängigkeit annehmen, werden Sie vom Compiler sofort gewarnt, die erforderlichen Weiterleitungsdeklarationen hinzuzufügen source1.h
. Dies stellt wiederum sicher, dass Header von ihren Angehörigen in beliebiger Reihenfolge aufgenommen werden können.
Beispiel:
source1.h
class Class1 {
Class2 c2; // a dependency which has not been forward declared
};
source1.cpp
#include "source1.h" // now compiler will alert you saying that Class2 is undefined
// so you can forward declare Class2 within source1.h
...
MSVC-Benutzer: Ich empfehle dringend, vorkompilierte Header zu verwenden. Verschieben Sie daher alle #include
Anweisungen für Standardheader (und andere Header, die sich nie ändern werden) nach stdafx.h
.
Schließen Sie von der spezifischsten zur am wenigsten spezifischen ein, beginnend mit der entsprechenden .hpp für die .cpp, falls eine solche vorhanden ist. Auf diese Weise werden alle versteckten Abhängigkeiten in Header-Dateien aufgedeckt, die nicht autark sind.
Dies wird durch die Verwendung vorkompilierter Header erschwert. Eine Möglichkeit, dies zu umgehen, besteht darin, ohne den Projekt-Compiler spezifisch zu machen, einen der Projekt-Header als vorkompilierte Header-Include-Datei zu verwenden.
In der C / C ++ - Welt ist dies eine schwierige Frage, da so viele Elemente über den Standard hinausgehen.
Ich denke, die Reihenfolge der Header-Dateien ist kein ernstes Problem, solange sie kompiliert werden, wie Squelart sagte.
Meine Ideen sind: Wenn in all diesen Headern kein Symbolkonflikt besteht, ist jede Reihenfolge in Ordnung, und das Problem mit der Headerabhängigkeit kann später behoben werden, indem dem fehlerhaften .h Zeilen #include hinzugefügt werden.
Der eigentliche Ärger entsteht, wenn ein Header seine Aktion ändert (indem er die # if-Bedingungen überprüft), je nachdem, welche Header oben stehen.
In stddef.h in VS2005 gibt es beispielsweise Folgendes:
#ifdef _WIN64
#define offsetof(s,m) (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
Nun das Problem: Wenn ich einen benutzerdefinierten Header ("custom.h") habe, der mit vielen Compilern verwendet werden muss, einschließlich einiger älterer, die nicht offsetof
in ihren Systemheadern enthalten sind, sollte ich in meinen Header schreiben:
#ifndef offsetof
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
Und stellen Sie sicher, dass Sie den Benutzer #include "custom.h"
nach allen System-Headern offsetof
anweisen , andernfalls wird in der Zeile in stddef.h ein Makro-Neudefinitionsfehler angezeigt.
Wir beten darum, in unserer Karriere keine solchen Fälle mehr zu erleben.