Basisklasse undefiniert
-
HolyGrail schrieb:
Includiert Ihr generell (die Ihr mehr Erfahrung habt als ich) keine (eigene) Header-Files (in *.h) sondern deklariert nur die Klasse? Kann man das generalisieren, oder gibt es Ausnahmen?
Kurz gesprochen: Includiere was nötig ist, Deklariere was möglich ist

Sofern ich Includes vermeiden kann, mache ich das auch (Sprich sofern nur Pointer oder Referenzen im Header verwendet werden: Vorwärtsdeklaration; sonst include). Dies hat mehrere Vorteile, einer davon ist die reduzierte Compilezeit

cu André
-
inkluda schrieb:
...eine zentrale headerfile gibt in der alle anderen header included werden. alle .cpp-dateien inkludieren *ausschließlich* diesen header...
Dies halte ich nicht nur für ein sehr schlechtes Design, das ist auch eben dieses:
inkluda schrieb:
dadruch werden alle cpp-dateien von allen headern abhängig.
Eben darum...
inkluda schrieb:
jede header-änderung führt deshalb dazu, dass alle files neu kompiliert werden müssen. allerdings hat das auch einen großen vorteil: visual c++ kann precompiled header nur so mit maximaler effizienz verwenden, was die kompilierungsgeschwindigkeit teilweise enorm steigert.
Die Nachteile überwiegen aber:
1. Der Precompiled Header ist nicht ANSI C++ Standard
2. Die Kompilierungsgeschwindigkeit wird dadurch nur zu einen bestimmten Grad erhöht, bei großen Projekten kann genau das Gegenteil der Fall sein. Der Precompiled Header sollte wenn man ihn schon verwendet nur das enthalten was tatsächlich möglichst nie geändert wird
3. Warum umbedingt bei einer kleinen Änderung alles neu linken müssen?Es ist meines Erachtens immer besser die Abhängigkeiten zu minimieren (grade wenn bestimmte Dateien von mehreren Projektteilen verwendet werden), dadurch sinkt der Linkaufwand ohnehin schon erheblich, und es wird immer nur dort etwas neu gelinkt wo es unbedingt notwendig ist.
Ich persönlich bin aber schon aus einem anderen Grund gegen Precompiled Header: Wenn du mit unterschiedlichen Compilern arbeitest die entweder teilweise ohne Precompiled Header arbeiten, oder mit fixen (unterschiedlichen) Namen, kann das dazu führen das du, falls man Header in mehreren Projekten benutzt du immer noch irgendwelche "Dummydateien" hinzufügen musst damit der Compiler xyz glücklich wird...
Warum abhängigkeiten überhaupt maximieren, und nicht einfach durch ein sauberes Design die Linkzeit reduzieren und Probleme vermeiden?
cu André
-
asc schrieb:
1. Der Precompiled Header ist nicht ANSI C++ Standard
aha. und? wenn ich auf meiner zielplattform mein projekt 10x schneller kompilieren kann ist mir das ziemlich egal.
außerdem spielt es keine rolle, weil es für andere compiler transparent ist. entweder sie werden angelegt und genutzt oder nicht. kompilieren tuts in jedem fall.2. Die Kompilierungsgeschwindigkeit wird dadurch nur zu einen bestimmten Grad erhöht, bei großen Projekten kann genau das Gegenteil der Fall sein.
ist mir aber noch nie passiert und ich arbeite an relativ großen projekten (eines davon ~600k LOC)
3. Warum umbedingt bei einer kleinen Änderung alles neu linken müssen?
visual c++ kompiliert mit den richtigen header-einstellungen 100 dateien in der gleichen zeit wie es ohne precompiled header nur 10 dateien schafft (schätzung, ich hab die zeit nicht gemessen). da ist der break-even schnell erreicht.
natürlich gibt es szenarien, in denen es ohne ph vielleicht kurzfristig schneller ginge (z.b. tweaking von irgendwelchen werten im header einer basisbibliothek).Warum abhängigkeiten überhaupt maximieren, und nicht einfach durch ein sauberes Design die Linkzeit reduzieren und Probleme vermeiden?
ich bin bisher bei großen projekten mit meinem ansatz gut gefahren und in jedem projekt in das ich eingestiegen bin, wurde mir mir bessere effizienz bescheinigt, nachdem ein projekt von deinem modell auf meins umgestellt wurde.
zugegebenermaßen waren mehrere unterschiedliche compiler dabei nie ein thema.theoretisch mag dein ansatz der sauberere sein, in der praxis fährt man meiner erfahrung nach besser mit meinem ansatz. ich habe vor ein paar jahren noch den gleichen standpunkt wie du vehement vertreten, wurde aber zwischenzeitlich eines besseren belehrt.
-
inkluda schrieb:
3. Warum umbedingt bei einer kleinen Änderung alles neu linken müssen?
visual c++ kompiliert mit den richtigen header-einstellungen 100 dateien in der gleichen zeit wie es ohne precompiled header nur 10 dateien schafft (schätzung, ich hab die zeit nicht gemessen). da ist der break-even schnell erreicht.
natürlich gibt es szenarien, in denen es ohne ph vielleicht kurzfristig schneller ginge (z.b. tweaking von irgendwelchen werten im header einer basisbibliothek).Das gilt aber afaik nur, wenn der präcompilte Header halbwegs stabil ist - wenn sich dort ständig etwas ändert, hast du ein Problem: Statt nur die 2 Quellfiles neu zu compilieren, die wirklich etwas mit der Änderung zu tun haben, mußt du alle Quelldateien des Projekts neu compilieren.
(PS: Wie groß sind denn die Projekte, die du üblicherweise bearbeitest?)
-
(PS: Wie groß sind denn die Projekte, die du üblicherweise bearbeitest?)
multimedia-projekte, auch spiele, im bereich von 100k bis 1mio loc.
was noch dazu gesagt werden muss: natürlich hängen dabei nicht alle dateien im gleichen .vcproj, sondern sind normalerweise auf verschiedene libs verteilt, die unabhängig voneinander kompiliert werden. wenn man ein einzelnes makefile mit 3000 files hat, geht die rechnung wahrscheinlich nicht mehr auf.
-
inkluda schrieb:
(PS: Wie groß sind denn die Projekte, die du üblicherweise bearbeitest?)
multimedia-projekte, auch spiele, im bereich von 100k bis 1mio loc.
Und wieviele Klassen sind daran beteiligt?
(btw, wenn du alle Klassenheader in die "stdafx.h" reinpackst, mußt du auch wieder auf die Reihenfolge achten)
-
CStoll schrieb:
Und wieviele Klassen sind daran beteiligt?
uff, nie gezählt. wenn ich das aktuelle (halbfertige) projekt anschaue: 1084 .cpp und .h dateien, also geschätzte 550 bis 600 klassen.
(btw, wenn du alle Klassenheader in die "stdafx.h" reinpackst, mußt du auch wieder auf die Reihenfolge achten)
weiß nicht ob stdafx.h irgendwelche besonderen anforderungen hat. ich habe eine solche datei nicht in meinen projekten, weil ich alles von hand einstelle ohne assistenten.
generell muss man natürlich die abhängigkeiten der header untereinander beachten, was sich in der reihenfolge im master-header niederschlägt.
-
inkluda schrieb:
uff, nie gezählt. wenn ich das aktuelle (halbfertige) projekt anschaue: 1084 .cpp und .h dateien, also geschätzte 550 bis 600 klassen.
...aufgeteilt in 12 subprojekte.
-
inkluda schrieb:
(btw, wenn du alle Klassenheader in die "stdafx.h" reinpackst, mußt du auch wieder auf die Reihenfolge achten)
weiß nicht ob stdafx.h irgendwelche besonderen anforderungen hat. ich habe eine solche datei nicht in meinen projekten, weil ich alles von hand einstelle ohne assistenten.
generell muss man natürlich die abhängigkeiten der header untereinander beachten, was sich in der reihenfolge im master-header niederschlägt.Genau das meinte ich ("stdafx.h" ist der Default-Name, den VS dem präcompiled Header verpasst). Und imho ist es wesentlich schwieriger, die Reihenfolge der Header dort aktuell zu halten als wenn du überall genau die Header einbindest, die du benötigst. (das ergibt schon genug Abhängigkeiten zwischen den einzelnen Klassen)
(in einen gemeinsamen Master-Header oder Precompiled Header sollten nur Sachen rein, von denen du weißt, daß sie auf absehbare Zeit nicht angefasst werden - und die vom gesamten Projekt benötigt werden (z.B. AFX-Header))
-
CStoll schrieb:
(in einen gemeinsamen Master-Header oder Precompiled Header sollten nur Sachen rein, von denen du weißt, daß sie auf absehbare Zeit nicht angefasst werden - und die vom gesamten Projekt benötigt werden (z.B. AFX-Header))
wie soll das aussehen? wenn man precompiled header verwendet, darf man doch im .cpp nichts anderes includieren außer den master header (sonst "precompiled header directive not found"). außer vielleicht in diesem "use precompiled header automatically"-modus, der allerdings auch ein gutes stück langsamer ist als es konsequent durchzuziehen.
CStoll schrieb:
Und imho ist es wesentlich schwieriger, die Reihenfolge der Header dort aktuell zu halten als wenn du überall genau die Header einbindest, die du benötigst.
wenn das projekt von anfang an so aufgebaut ist, muss man neue header einfach nur an der richtigen stelle einfügen. wir hatten damit bisher noch nie probleme.
existierende projekte so umzubauen ist natürlich aufwendiger, aber man muss es ja nur einmal machen.
-
inkluda schrieb:
CStoll schrieb:
(in einen gemeinsamen Master-Header oder Precompiled Header sollten nur Sachen rein, von denen du weißt, daß sie auf absehbare Zeit nicht angefasst werden - und die vom gesamten Projekt benötigt werden (z.B. AFX-Header))
wie soll das aussehen? wenn man precompiled header verwendet, darf man doch im .cpp nichts anderes includieren außer den master header (sonst "precompiled header directive not found"). außer vielleicht in diesem "use precompiled header automatically"-modus, der allerdings auch ein gutes stück langsamer ist als es konsequent durchzuziehen.
Wenn du precompiled Header verwendet, darf nichts vor dem
#include "stdafx.h"stehen - dahinter sind andere Header erlaubt.CStoll schrieb:
Und imho ist es wesentlich schwieriger, die Reihenfolge der Header dort aktuell zu halten als wenn du überall genau die Header einbindest, die du benötigst.
wenn das projekt von anfang an so aufgebaut ist, muss man neue header einfach nur an der richtigen stelle einfügen. wir hatten damit bisher noch nie probleme.
existierende projekte so umzubauen ist natürlich aufwendiger, aber man muss es ja nur einmal machen.Und was, wenn du erst im Nachhinein feststellst, daß sich zwei gegebene Klassen doch brauchen?
(außerdem bleibt noch immer das Problem der unnötigen Abhängigkeiten - wenn du zu irgendeiner Klasse den Header änderst, mußt du dein gesamtes Projekt neu compilieren, weil JEDE andere Klasse diesen Header (indirekt) einbindet - bei mir müssen nur die Klassen neu durch den Compiler, die etwas mit der geänderten Klasse zu tun haben)
-
inkluda schrieb:
asc schrieb:
1. Der Precompiled Header ist nicht ANSI C++ Standard
aha. und? wenn ich auf meiner zielplattform mein projekt 10x schneller kompilieren kann ist mir das ziemlich egal.
außerdem spielt es keine rolle, weil es für andere compiler transparent ist. entweder sie werden angelegt und genutzt oder nicht. kompilieren tuts in jedem fall....Ich denke, Du übersiehst, dass "Abhängigkeit" kein technisches Problem ist, sondern ein fachliches. Und dieses fachliche Problem schaffst Du Dir mit einer technischen Maßnahme....
Spätestens wenn Du Deine Sourcen mehrfach verwendest (in unterschiedlichen Versionen oder Projekten), schießt Du Dir mit dieser Vorgehensweise übelst ins Knie.
Z.B. ein ganz normales Szenario:Utilities: ---------- Module (includieren jeweils all_headers.h): - ausgabe.cpp - simulation.cpp - kommunikation.cpp Header: - ausgabe.h - simulation.h - kommunikation.h - all_headers.h (includieren ausgabe.h, simulation.h und kommunikation.h) Produkt X: --------- Modul: - xKram.cpp includiert: all_headers.h linkt: ausgabe.cpp, simulation.cpp Produkt Y: --------- Modul - yKram.cpp includiert: all_headers.h linkt: kommunikation.cpp- Produkte X und Y sind bereits an jeweils 20 Kunden ausgeliefert und in Betrieb.
- Nun stellst Du einen Bug (oder Optimierungsmöglickeit, ...) in simulation.h fest.
- => Du musst ALLE Module neu compilieren und linken (ausgabe.cpp, simulation.cpp, kommunikation.cpp,xKram.cpp, yKram.cpp) und
- nicht nur die X-Kunden,
- sondern auch die Y-Kunden neu beliefern (obwohl die das simulation-Modul gar nicht nutzen).
Einerseits sehr häßlich aufwendig und kundenunfreundlich ... andererseits ist DER Rebuild garantiert nicht mehr schneller als wenn Du nur ein Projekt builden musst.
Um so etwas zu vermeiden, hat man Modularisierung erfunden - vor ca. 20 Jahren - und sie hat sich seitdem bewährt.
Nach meiner Erfahrung sind sowieso Buildzeiten das schwächste Argument, das erst dann zur Geltung kommt, wenn alle anderen (fachlichen und technischen Argumente) keine Entscheidung vorgeben...Gruß,
Simon2
-
CStoll schrieb:
Und was, wenn du erst im Nachhinein feststellst, daß sich zwei gegebene Klassen doch brauchen?
geht nicht. wenn ich es mit einer forward declaration nicht lösen kann, dann habe ich sowieso ein problem, precompiled header hin oder her. oder verstehe ich die frage falsch?
Simon2 schrieb:
[zeug]
alles schön und richtig. fakt bleibt: ich habe mehrere größere projekte so auf- oder umgebaut, es gab nie probleme. im gegenteil: bei den umgebauten haben immer alle beteiligten einhellig gesagt, dass sie nachher flüssiger arbeiten konnten, weil die kompilierung insgesamt schneller ablief.
deine argumente mögen fachlich und der theorie korrekt sein und für bestimmte projekte mag meine herangehensweise vielleicht ineffizient sein. ich hab aber noch kein solches gesehen (was nicht heißt, dass es sie nicht gibt). ich habe vor ein paar jahren noch genau das gleiche wie du erzählt. bis ich es an einem größeren projekt mal ausprobiert habe.
Um so etwas zu vermeiden, hat man Modularisierung erfunden - vor ca. 20 Jahren - und sie hat sich seitdem bewährt.
richtig und deshalb sind alle meine projekte auch modularisiert aufgebaut. es gibt ein modul fürs audio, eins für eingabegeräte, eine für die grafik, etc... alles schön in libraries verpackt. und jede hat einen masterheader.
Simon2 schrieb:
Spätestens wenn Du Deine Sourcen mehrfach verwendest (in unterschiedlichen Versionen oder Projekten), schießt Du Dir mit dieser Vorgehensweise übelst ins Knie.
nein, denn source der projektübergreifend verwendet werden soll, ist natürlich ein eigenständiges projekt und wird in eine lib kompiliert.