programming - C/C++ enthält Dateireihenfolge/Best Practices




c++ programming (7)

Gibt es eine empfohlene Reihenfolge, in der Include-Dateien angegeben werden sollten?

Gehen beispielsweise die Systemdateien, STL und Boost vor oder nach den lokalen Include-Dateien?

Gibt es einen besonderen Grund, sich für das eine oder andere zu entscheiden? Ich nehme an, Include-Dateien haben die richtigen Abhängigkeiten angegeben.


Das Wichtigste ist, dass Ihre Header nicht davon abhängig sein sollten, dass andere Header zuerst eingefügt werden. Eine Möglichkeit, dies zu gewährleisten, besteht darin, die Header vor allen anderen Headern einzufügen.

"Thinking in C ++" erwähnt dies insbesondere und bezieht sich auf Lakos "Large Scale C ++ Software Design":

Latente Verwendungsfehler können vermieden werden, indem sichergestellt wird, dass die .h-Datei einer Komponente selbst analysiert - ohne von außen bereitgestellte Deklarationen oder Definitionen ... Durch die Aufnahme der .h-Datei als allererste Zeile der .c-Datei wird sichergestellt, dass keine kritische Komponente vorhanden ist Informationen, die der physischen Schnittstelle der Komponente innewohnen, fehlen in der .h-Datei (oder, falls vorhanden, dass Sie davon erfahren werden, sobald Sie versuchen, die .c-Datei zu kompilieren).

Das heißt, in der folgenden Reihenfolge einschließen:

  1. Der Prototyp / Interface-Header für diese Implementierung (dh die .h / .hh-Datei, die dieser .cpp / .cc-Datei entspricht).
  2. Andere Header aus dem gleichen Projekt, je nach Bedarf.
  3. Header aus anderen Nicht-Standardbibliotheken (z. B. Qt, Eigen usw.).
  4. Header aus anderen "fast-Standard" -Bibliotheken (zum Beispiel Boost)
  5. Standard-C ++ - Header (z. B. iostream, funktional usw.)
  6. Standard-C-Header (z. B. cstdint, dirent.h usw.)

Wenn einer der Header ein Problem mit der Aufnahme in diese Reihenfolge hat, beheben Sie sie entweder (falls Sie Ihre sind) oder verwenden Sie sie nicht. Boykott-Bibliotheken, die keine sauberen Header schreiben.

Googles C ++ Style Guide argumentiert fast das Gegenteil, mit wirklich überhaupt keinen Rechtfertigungen; Ich persönlich bevorzuge den Ansatz von Lakos.


Das ist nicht subjektiv. Stellen Sie sicher, dass Ihre Header nicht darauf angewiesen sind, dass #include d in einer bestimmten Reihenfolge enthalten ist. Sie können sicher sein, dass es egal ist, in welcher Reihenfolge Sie STL- oder Boost-Header einfügen.


Fügen Sie vom spezifischsten zum am wenigsten spezifischen hinzu, beginnend mit der entsprechenden .hpp-Datei für die .cpp-Datei, falls eine solche existiert. Auf diese Weise werden alle versteckten Abhängigkeiten in Header-Dateien aufgedeckt, die nicht autark sind.

Dies wird durch die Verwendung von vorkompilierten Headern kompliziert. Eine Möglichkeit ist, ohne dass Ihr Projekt compilerspezifisch ist, einen der Projektheader als vorkompilierte Header-Include-Datei zu verwenden.


Fügen Sie zuerst die Kopfzeile ein, die der .cpp-Datei entspricht. Mit anderen Worten: source1.cpp sollte source1.h bevor etwas anderes source1.h . Die einzige Ausnahme, die ich mir vorstellen kann, ist die Verwendung von MSVC mit vorkompilierten Headern. In diesem Fall müssen Sie vor allem anderen stdafx.h .

Begründung: Durch das Einschließen von source1.h vor anderen Dateien wird sichergestellt, dass es source1.h seinen Abhängigkeiten stehen kann. Wenn source1.h eine Abhängigkeit von einem späteren Datum source1.h , wird der Compiler Sie sofort darauf source1.h , die erforderlichen Weiterleitungsdeklarationen zu 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 also alle #include Anweisungen für Standardheader (und andere Header, die sich nie ändern) nach stdafx.h .


Ich denke nicht, dass es eine empfohlene Reihenfolge gibt, solange es kompiliert wird! Was nervig ist, ist, wenn einige Header erfordern, dass andere Header zuerst eingefügt werden ... Das ist ein Problem mit den Headern selbst, nicht mit der Reihenfolge der Includes.

Meine persönliche Präferenz ist es, von lokal nach global zu gehen, jede Untersektion in alphabetischer Reihenfolge, dh:

  1. h-Datei, die dieser cpp-Datei entspricht (falls zutreffend)
  2. Header aus der gleichen Komponente,
  3. Header von anderen Komponenten,
  4. System-Header.

Mein Grundgedanke für 1. ist, dass es beweisen sollte, dass jeder Header (für den es eine cpp gibt) #include ohne Voraussetzungen enthalten sein kann. Und der Rest scheint nur logisch von dort zu fließen.


Ich empfehle:

  1. Die Kopfzeile für das .cc-Modul, das Sie erstellen. (Stellt sicher, dass jeder Header in Ihrem Projekt keine impliziten Abhängigkeiten zu anderen Headern in Ihrem Projekt aufweist.)
  2. C Systemdateien.
  3. C ++ Systemdateien.
  4. Platform / OS / andere Header-Dateien (zB win32, gtk, openGL).
  5. Andere Headerdateien aus Ihrem Projekt

Und natürlich alphabetische Reihenfolge innerhalb jedes Abschnitts, wo es möglich ist.

Verwenden Sie immer Vorwärtsdeklarationen, um unnötige #include s in Ihren Header-Dateien zu vermeiden.


Um meinen eigenen Stein an die Wand zu bringen.

  1. Jeder Header muss autark sein, was nur getestet werden kann, wenn er mindestens einmal enthalten ist
  2. Man sollte nicht fälschlicherweise die Bedeutung eines Headers eines Drittanbieters ändern, indem man Symbole (Makros, Typen usw.) einführt.

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 wird durch eine Leerzeile vom nächsten getrennt:

  • Kopfzeile, die dieser CPP-Datei entspricht (Plausibilitätsprüfung)
  • Systemkopfzeilen
  • Header von Drittanbietern, geordnet nach Abhängigkeitsreihenfolge
  • Projektheader
  • Projekt private Header

Beachten Sie außerdem, dass sich jede Datei abgesehen von Systemheadern in einem Ordner mit dem Namen ihres Namespace befindet, nur weil es einfacher ist, sie auf diese Weise zu verfolgen.





c