Headerdateien "inlude" immer wieder neu?
-
Stromberg schrieb:
Äh was genau ist den so ein "smartpointer"? Was bringt mir des auf das struct einen Zeiger zu legen....?
Beginnen wir bei Smartpointern:
Ein Smartpointer ist ein Objekt das sie fast wie ein Zeiger verhält, aber um die Speicherfreigabe kümmtert. Es gibt verschiedene Formen hiervon. Die einfachen (wie scoped_ptr) übernehmen im wesentlichen nur den Aufruf von delete am Ende ihrer Lebenszeit.
Minibeispiel:
#include <boost/smart_ptr.hpp> void foo1() { scoped_ptr<int> value(new int(4)); } // <-- hier wird der Wert automatisch gelöscht void foo2() { int* value = new int(4); delete value; // hier muss es manuell erfolgen }Was ist an sich der Vorteil? Nehmen wir mal an das die Funktion länger ist und mehrere Austritspunkte (return/exception...) hat. Bei ein Zeiger müsstest du in jeden Fall dann extra ein delete schreiben, beim Smartpointer wird dies (unabhängig wo die Methode beendet wird) automatisch durch seinen Destruktor gemacht.
Dann gibt es aber noch die komplizierteren wie shared_ptr die Referenzzählung betreiben und sich so direkt nicht durch Zeiger simulieren lassen. Der Sinn hiervon ist, das man diese Kopieren kann, und erst mit dem löschen der letzten Smartpointerinstanz der Zeiger gelöscht wird. Was man vermeiden muss ist aber das Objekte sich dabei gegenseitig am Leben halten.
Warum nun einen Zeiger im Header auf die Struktur?
Man kann Zeiger und Referenzen im Gegensatz zu Werten ohne Kenntnis ihres genauen Typs definieren (Stichwort: Vorwärtsdeklaration). Erst mit dem Zugriff auf den Wert muss der Typ bekannt sein.
Minibeispiel:
// foo.h (Includeguards etc. als Beispiel weggelassen) class A; // <-- nur Vorwärtsdeklaration void foo(const A& value); // <-- Hier kein genauer Typ nötig // cpp #include "foo.h #include "A.h" // s.u. void foo(const A& value) { A->foo(); // Hier wird zugegriffen, daher Typ nötig (und daher include) }Man sollte an sich möglichst wenig includes im Header machen (wegen Compilezeiten), daher Zeiger/Referenzen und Vorwärtsdeklarationen.
cu André
-
Na, wir haben doch im Magazin einen ausführlichen Smart-Pointer-Artikel.
Lest ihr das Magazin nicht
?
-
Artchi schrieb:
Na, wir haben doch im Magazin einen ausführlichen Smart-Pointer-Artikel.
Lest ihr das Magazin nicht
?Lesen oder Überfliegen schon, aber immer daran denken: nein ;p
-
Ik mach die ganzen Scherze mit dem Zeiger nur das meine Compilierzeit kürzer wird, wa? Mehr bringt mir das nischt?
Ich mein, wenn da eine "include" Datei mehr oder weniger im Header drinsteht, dann is es halt eine hunfertstel sekunde langsamer...aber des kann einem doch egal sein oder? Auf was es doch zum Schluss ankommt, dass ist doch die ".exe" oder ".o" Datei, und die sind dadurch ja nicht langsamer oder?
Aber mir is es glaub eigentlich egal, ob ich 1sek oder 6sek compiliere. Oder gibts da noch größere Zeitunterschied?
Wenns mal n Unterschied zwischen 10sek und 10std is, okay, dann überleg ichs mir nochmal
MfG
Stromberg
-
Stromberg schrieb:
Wenns mal n Unterschied zwischen 10sek und 10std is, okay, dann überleg ichs mir nochmal

Nur als grobe Angabe mal in den Raum geschmissen: An der Arbeit habe ich bei Teilprojekten Linkzeiten von bis zu 8 Minuten. Das Gesamtprojekt linkt in nicht weniger als 2-3 Stunden.
Okay, die Entwicklungsumgebung ist eh nicht wirklich gut, aber es gibt irgendwann dennoch Größenordnungen wo man darüber nachdenkt.
cu Andé
-
Okay, da hab ihr dann aber doch auch so 100000 Zeilen Code oder? Was für eine IDE benutzt ihr den da? Was für IDE's benutzt man für so große Projekte, und was für n Compiler? würd mich ma interessieren.
MfG
Stromberg
-
Stromberg schrieb:
Okay, da hab ihr dann aber doch auch so 100000 Zeilen Code oder? Was für eine IDE benutzt ihr den da? Was für IDE's benutzt man für so große Projekte, und was für n Compiler? würd mich ma interessieren.
Es sind zwei IDE's/Compiler (was besonders die Kommunikation erschwert) und beides sind Dinosaurier... Ansi C++, STL? Wäre schön. Der eine ist Visual Studio 6.0 Professionell, der andere eine schon mehr als 8 Jahre lang eingestellte Rad-Umgebung von Sybase, daher keine Erwähnung wert.
Wenn ich es neu aufsetzen würde, wäre die Umgebung wohl (wegen den Anforderungen, und Rahmenbedingungen) Visual Studion 2008 Prof (oder höher) mit C# und C++/CLI oder rein auf C++ Basis (wohl dann mit der MFC auch wenn ich persönlich die MFC eher verabscheue).
Das Projekt dürfte so in der Größenordung um die 10 Millionen Zeilen Code liegen, und je nach dem ob man externe Komponenten und Reports zurechnet ist das fertige Programm zwischen 90 und 390 MB groß...
cu André
-
Naja, man kompiliert ja nicht jedesmal das komplette Projekt, wenn man eine Änderung macht. Meistens macht man Änderungen in der Implementierung (.cpp) und dann wird nur diese eine Datei kompiliert. Passiert eine Änderung im Header, kompiliert natürlich mehr. Kommt also darauf an, ob man viel in Headern ändert.
Achja, man kann auch die Zeit verkürzen, in dem man PCHs benutzt.
Das Linken kann man verkürzen, in dem man viel in dynamisch gelinkte Libs auslagert. Usw. usf. Also 2 bis 3 Stunden für eine EXE halte ich irgendwie für komisch. Für ein gesamtes Projekt (mehrere Libs usw.) ist es aber verständlich. Aber ändert man immer in allen Projekten gleichzeitig was? Habe die Erfahrung gemacht, das man immer nur in ganz bestimmten Teilprojekten aktiv ist.
-
Was hier ordentlich Zeit spart ist ein Shared Repository mit Nightly Builds dessen Objektdateien immer dann verwendet werden, wenn lokal keine Änderungen vorliegen.
-
Artchi schrieb:
Das Linken kann man verkürzen, in dem man viel in dynamisch gelinkte Libs auslagert. Usw. usf. Also 2 bis 3 Stunden für eine EXE halte ich irgendwie für komisch. Für ein gesamtes Projekt (mehrere Libs usw.) ist es aber verständlich.
Ich habe auch nie was anderes gesagt (Gesamtprojekt nicht unter 2-3 Stunden). Die Einzelprojekte (überwiegend dll's linken in maximal 8 Minuten, wobei die IDE manchmal meint erstmal wegen einer winzigen Änderung an der UI 5+ Minuten in 100% Auslastung verfallen zu müssen...
cu André
-
asc schrieb:
...wobei die IDE manchmal meint erstmal wegen einer winzigen Änderung an der UI 5+ Minuten in 100% Auslastung verfallen zu müssen...
Meine nicht, dass das mit Visual Studio 2005+ besser würde

-scnr-
-
LordJaxom schrieb:
asc schrieb:
...wobei die IDE manchmal meint erstmal wegen einer winzigen Änderung an der UI 5+ Minuten in 100% Auslastung verfallen zu müssen...
Meine nicht, dass das mit Visual Studio 2005+ besser würde

In VC2005+ bin ich aber je nach Sprache aber auch etwas flexibler mit den Designern (z.B. gebe ich persönlich XAML bei WPF unter C# eh händisch ein xD). Zu dem MFC und WinForms Designer kann ich aber nichts sagen. Das letzte mal das ich mit dem MFC Designer etwas gemacht habe war zu VC 1.5 Zeiten...
cu André
-
Irgendwie hab ich das immer noch nicht genau kapiert, wie man ein "struct" mittels einens Zeigers Vorwärtsdeklarieren soll, wenn dieses Typen enthält die erst in den include Dateien von der .cpp vorkommen, und man wegen der Compilierzeit diese nicht im Header laden möchte.
Schätzungsweise ich hab folgendes struct im Header, mit den Deklarationen:
crypt.hppstruct test { fstream file; vector<int> a; string b; };Was genau mach ich jetzt in "crypt.hpp" noch dass das läuft, und was genau mach ich in crypt.cpp? Also in .hpp muss jetzt erst mal irgednwie ein Zeiger auf ein struct Objekt gelegt werden ( machen wir das bitte mit Zeigern, später schau ich mir mal smarpointer an).
Kann mir jemand n Beispiel geben?MfG
Stromberg
-
Stromberg schrieb:
Irgendwie hab ich das immer noch nicht genau kapiert, wie man ein "struct" mittels einens Zeigers Vorwärtsdeklarieren soll, wenn dieses Typen enthält die erst in den include Dateien von der .cpp vorkommen, und man wegen der Compilierzeit diese nicht im Header laden möchte.
Nehmen wir nochmal ein vereinfachtes Beispiel:
// A.h class A { private: struct AImpl; AImpl* Implementation; A(const A&); A& operator=(const A&); public: A(); ~A(); };// A.cpp #include "A.h" struct A::AImpl { public: int a; int b; }; A::A() : Implementation(new AImpl()) {} A::~A() { delete Implementation; };Du nutzt hierbei folgendes aus (Vereinfacht gesagt): Der Typ von einem Element das als Zeiger oder Referenz verwendet wird, muss erst bei der Verwendung vollständig deklariert und definiert sein (es reicht eine Vorwärtsdeklaration). Und da du im Header nirgens eine Zeigerreferenzierung machst, brauchst du es dort auch noch nicht genau anzugeben. Im Source aber referenzierst du es, und benötigst dadurch auch die Informationen.
Sprich, das Handle-Body Idiom basiert darauf das man alle Membervariablen der Klasse in den Source auslagert (Der Zugriff erfolgt dann indirekt über den Zeiger). Dadurch kann man in der Regel viele Includes im Header erst einmal weglassen. Beim Linken wird dadurch Zeit gespart.
cu André
P.S: Auch hier habe ich den Zuweisungsoperator/Kopierkonstruktor der Einfachheit halber weggelassen, da du dabei bedenken musst den Inhalt zu kopieren da du mit Zeigern arbeitest (tiefe Kopie).
-
// A.h class A { private: struct AImpl; //Das hier ist die Vorwärtsdeklaration! AImpl* Implementation; // Kann man machen weil bei Zeigern erst bei der Verwendung die Definition + Deklaration benötigt wird A(const A&); A& operator=(const A&); public: A(); ~A(); };Äh "struct AImpl" könnt ich aber auch außerhalb der Klasse Vorwärtsdeklarieren?
Und die Deklaration darf nur in der .cpp sein, is ja logisch, weil in der .hpp sin die Header noch nicht vorhanden (darum machen wir des ja mit dem Zeiger)
Ich glaub ich habs verstanden.MfG
Stromberg
-
Stromberg schrieb:
Äh "struct AImpl" könnt ich aber auch außerhalb der Klasse Vorwärtsdeklarieren?
Ja, sollte man aber hierbei nicht machen da es Implementierungsdetails sind.
Und nein, du sollst es jetzt nicht für jeden deiner Header so machen, aber es macht durchaus Sinn wenn du dadurch sehr viele Includes auslagern kannst (oder andere Gründe hast deine Deklaration noch nicht im Header zu machen).
cu André