Globaler Header oder Einzelne Dateien



  • Hi,

    ich hab bisher nur kleine Projekte in C++ realisiert.

    Jetzt möchte ich mich an ein etwas größeres Projekt wagen.

    Bisher hatte ich immer ein Main-Header, wo alle Klassen-Header includiert wurden.
    Dieses Main-Header File habe ich immer in alle Sourcedateien inkludiert.

    Kann man das bei größeren Projekten auch so machen, oder sollte man in jeder Source-Datei nur das inkludieren, was gebraucht wird?

    Wie schaut es bei großen Projekten mit der Compiliergeschwindigkeit aus?

    Gruß



  • Schwarzefee schrieb:

    sollte man in jeder Source-Datei nur das inkludieren, was gebraucht wird?

    ^



  • Schwarzefee schrieb:

    Kann man das bei größeren Projekten auch so machen, oder sollte man in jeder Source-Datei nur das inkludieren, was gebraucht wird?

    Dies.

    C++ kompiliert ätzend langsam und bei globalem Header wirkt sich jede Änderung auf alle Sourcedateien aus.


  • Mod

    Vor allem sollte man auch in Headern möglichst nur Vorwärtsdeklarationen stehen haben, wenn nur Referenzen/Zeiger auf eine Klasse vorhanden sind. Also <iosfwd> statt <o/istream> und

    class X;
    // statt
    #include "X.h"
    


  • Arcoth schrieb:

    Also <iosfwd> statt <o/istream>

    Nö, das bringt nichts (und dafür ist iosfwd auch nicht gedacht).

    Viele riesige Headers zu includen ist kein Problem, die sind schon im Cache und die Parser sind rasend schnell.

    Wo C++-Compiler langsam werden ist erst, wenn sie den Code in Maschinencode umwandeln. Deshalb muss man dafür sorgen, dass möglichst wenig Code kompiliert werden muss.

    Und da ist das Problem: Wenn du einen Header änderst, müssen alle Sourcedateien, die diesen indirekt includen, neu kompiliert werden. Auch wenn du nur ein private-Member änderst. Wenn du im ganzen Projekt eine zentrale Headerdatei hast und dort eine winzige Änderung machst, muss das ganze Projekt neu kompiliert werden. Und das nervt.

    Deshalb ist die Strategie: Die Header aus dem eigenen Projekt so zu designen, dass sich nichts ändert. Alles, was sich potentiell ändern könnte, soll in eine Source-Datei. Dann änderst du diese und nur die Source-Datei muss neu kompiliert werden, nicht alle Dateien, die der einen Klasse abhängen.

    Die Tricks dazu heissen pimpl und forward declarations, für mittelgrosse Projekte sollte aber gesunder Menschenverstand ausreichen. Minimiere Abhängigkeiten innerhalb deines Projektes.


  • Mod

    iowtf schrieb:

    Wo C++-Compiler langsam werden ist erst, wenn sie den Code in Maschinencode umwandeln. Deshalb muss man dafür sorgen, dass möglichst wenig Code kompiliert werden muss.

    Das ist eine ungültige Verallgemeinerung. Das kommt vor allem auf die Komplexität an. Die längsten Compilierungserlebnisse hat man normalerweise mit komplexen Templates, besonders wenn Metaprogrammierung ins Spiel kommt. Einfacher Anwendungscode hingegen geht sehr flott, selbst wenn es viel ist.



  • iowtf schrieb:

    Viele riesige Headers zu includen ist kein Problem, die sind schon im Cache und die Parser sind rasend schnell.

    Bist du sicher, dass das mit dem Cache so einfach ist? Die Semantik des Codes kann sich ja abhängig vom Ort des #include s dramatisch ändern -- nicht nur durch #define , sondern auch vorhandene Deklarationen für ADL, Überladungsauflösung oder Templatespezialisierungen. Bei Standardheadern kann der Compiler zwar etwas strikter sein, aber im Allgemeinen würde ich bezweifeln, dass ein Cache derart effizient ist.

    Genau für solche Szenarien gibt es doch vorkompilierte Header... Wenn das Cachen automatisch geschähe, sollte der Unterschied kaum bemerkbar sein. Ist er aber.

    iowtf schrieb:

    Wo C++-Compiler langsam werden ist erst, wenn sie den Code in Maschinencode umwandeln.

    Massiver Template-Code wie Boost ist jedenfalls recht langsam. Das Parsen selbst dauert wahrscheinlich nicht allzu lange, aber die Verarbeitung/Auflösung der internen Datenstrukturen... Zählst du diesen Schritt auch dazu?



  • iowtf schrieb:

    Arcoth schrieb:

    Also <iosfwd> statt <o/istream>

    Nö, das bringt nichts (und dafür ist iosfwd auch nicht gedacht).

    Sondern?



  • Nexus schrieb:

    iowtf schrieb:

    Wo C++-Compiler langsam werden ist erst, wenn sie den Code in Maschinencode umwandeln.

    Massiver Template-Code wie Boost ist jedenfalls recht langsam. Das Parsen selbst dauert wahrscheinlich nicht allzu lange, aber die Verarbeitung/Auflösung der internen Datenstrukturen... Zählst du diesen Schritt auch dazu?

    Ich meine damit den Schritt Parse-AST --> Obj-Datei.

    Header mit Metaprogrammierung sind idR recht flott geparsed, solange die nicht instanziert werden. Deshalb versucht man, die "Ausführung des Metaprogramming-Codes" möglichst in der Source-Datei zu haben. Und oft gelingt das.

    Mir ging es aber gar nicht darum. Die Leute, die die Standardbibliothek und Boost geschrieben haben, kennen sich mit der Thematik aus, und Anfänger wie Schwarzefee nicht, für die ist Metaprogramming aber erstmal irrelevant.

    volkard schrieb:

    iowtf schrieb:

    Arcoth schrieb:

    Also <iosfwd> statt <o/istream>

    Nö, das bringt nichts (und dafür ist iosfwd auch nicht gedacht).

    Sondern?

    Rückwärtskompatibilität, wurde eingeführt, als die iostreams zu Templates wurden.



  • iowtf schrieb:

    volkard schrieb:

    iowtf schrieb:

    Arcoth schrieb:

    Also <iosfwd> statt <o/istream>

    Nö, das bringt nichts (und dafür ist iosfwd auch nicht gedacht).

    Sondern?

    Rückwärtskompatibilität, wurde eingeführt, als die iostreams zu Templates wurden.

    Und nur um mich zu ärgern, wurde sie nicht <ioscompat> genannt. Das ist schrecklich gemein!


  • Mod

    Das ist schrecklich gemein!
    ➡

    volkard schrieb:

    Ich muß erstmal ein Viertelstündchen weinen. Bin bald wieder (geschwächt) da. Macht sowas besser nicht jeden Tag.



  • iowtf schrieb:

    Viele riesige Headers zu includen ist kein Problem, die sind schon im Cache und die Parser sind rasend schnell.

    Ähm, mit Template-Geraschel und argument-dependent lookup dauert's eeeewig. Erinnere Dich dran, wie es war, als die Templates neu waren. Schon mittelkleine Projekte kamen ohne zentralen nighly build nicht aus, weil ein Komplettbuild nicht unter 2 Stunden zu haben war.

    Okay, damals konnte man mit echt sparsamem Inkludieren und manchmal pimpl einiges reißen.

    Geändert hat sich nur: Heute haut so ein i7 die Ewigkeit in einer Kaffepause durch.

    iowtf schrieb:

    Wo C++-Compiler langsam werden ist erst, wenn sie den Code in Maschinencode umwandeln. Deshalb muss man dafür sorgen, dass möglichst wenig Code kompiliert werden muss.

    Dann müsste ccache viel bringen. Tut's bei mir aber nicht, hab's wieder ausgemacht.

    iowtf schrieb:

    Und da ist das Problem: Wenn du einen Header änderst, müssen alle Sourcedateien, die diesen indirekt includen, neu kompiliert werden.

    Da sind wir uns einig.



  • volkard schrieb:

    Dann müsste ccache viel bringen. Tut's bei mir aber nicht, hab's wieder ausgemacht.

    ccache bringt nur was, wenn sowohl alle Header, als auch das Source-File absolut identisch (gleicher Hash) sind. Heisst, es bringt was bei "make clean; make", aber sonst nichts.



  • iowtf schrieb:

    volkard schrieb:

    Dann müsste ccache viel bringen. Tut's bei mir aber nicht, hab's wieder ausgemacht.

    ccache bringt nur was, wenn sowohl alle Header, als auch das Source-File absolut identisch (gleicher Hash) sind. Heisst, es bringt was bei "make clean; make", aber sonst nichts.

    Bekannt.



  • volkard schrieb:

    iowtf schrieb:

    volkard schrieb:

    Dann müsste ccache viel bringen. Tut's bei mir aber nicht, hab's wieder ausgemacht.

    ccache bringt nur was, wenn sowohl alle Header, als auch das Source-File absolut identisch (gleicher Hash) sind. Heisst, es bringt was bei "make clean; make", aber sonst nichts.

    Bekannt.

    Wie folgerst du aus

    Wo C++-Compiler langsam werden ist erst, wenn sie den Code in Maschinencode umwandeln. Deshalb muss man dafür sorgen, dass möglichst wenig Code kompiliert werden muss.

    dann

    volkard schrieb:

    Dann müsste ccache viel bringen

    ?



  • iowtf schrieb:

    volkard schrieb:

    iowtf schrieb:

    volkard schrieb:

    Dann müsste ccache viel bringen. Tut's bei mir aber nicht, hab's wieder ausgemacht.

    ccache bringt nur was, wenn sowohl alle Header, als auch das Source-File absolut identisch (gleicher Hash) sind. Heisst, es bringt was bei "make clean; make", aber sonst nichts.

    Bekannt.

    Wie folgerst du aus

    Wo C++-Compiler langsam werden ist erst, wenn sie den Code in Maschinencode umwandeln. Deshalb muss man dafür sorgen, dass möglichst wenig Code kompiliert werden muss.

    dann

    volkard schrieb:

    Dann müsste ccache viel bringen

    ?

    Weil ccache noch billiger nur präprozessiert und dann damit nachschaut und bei mir üblicherweise ca 50% Treffer hatte, also ganz massig "Code in Maschinencode umwandeln" einspart.


Log in to reply