Programiersprache für Anfänger
-
Auch PCHs (Precompiled Headers) können die intensive und komplexe Templates drastisch in der Compilezeit reduzieren. PCH muß man natürlich auch explizit einschalten, wird wahrscheinlich auch wieder ein Contra-Argument der hiesigen Java-/C#-Fraktion sein, weil man ja wieder einen COmpiler-Switch extra lernen muß.
-
HansiHinterseher schrieb:
PCH muß man natürlich auch explizit einschalten, wird wahrscheinlich auch wieder ein Contra-Argument ... sein, weil man ja wieder einen COmpiler-Switch extra lernen muß.
Und ist zudem Compilerabhängig. Sofern sich das nicht durch irgendwelche Änderungen an den Sourcen umsetzen lässt, okay. Aber wenn du (wie ich durchaus schon musste) mit mehreren Compilern paralell arbeitest, ist es ein Problem wenn diese die PCH unterschiedlich umsetzen, und die Sourcen ein Compilerabhängiges Include etc. benötigen.
cu André
-
~john schrieb:
tfa schrieb:
Was passiert, wenn ich ein Objekt anlege und es in z.B. eine Liste/Hashtabelle o.ä. einfüge und erst Stunden später wieder lösche? Das ist doch dann auch Handarbeit. Ein GC ist da schon mächtiger.
Nein, mit einem GC hat man exakt das gleiche Problem. Man muß sich immer Gedanken darüber machen, wie die Lebenszeit eines Objekt aussehen soll.
aber nur in seltenen ausnahmen. ein objekt, auf das es keinen verweis mehr gibt, oder objekte die sich gegenseitig referenzieren, aber auf keins davon mehr ein verweis im aktiven code besteht, schmeisst der GC irgendwann automatisch weg. funktioniert in 99% aller fälle wunderbar, ohne dass sich der programmierer darüber gedanken machen muss. und wenn dieses standard-verhalten mal nicht passt, bietet z.B. Java noch sogenannte weak-, soft- und phantom-references an.
-
~fricky schrieb:
aber nur in seltenen ausnahmen. ein objekt, auf das es keinen verweis mehr gibt, oder objekte die sich gegenseitig referenzieren, aber auf keins davon mehr ein verweis im aktiven code besteht, schmeisst der GC irgendwann automatisch weg.
Du hast den wichtigen Punkt übersehen "auf das es keinen verweis mehr gibt". Wenn diese Bedingung erfüllt ist, wir mit RC das Objekt ebenfalls abgeräumt. Die Ausnahme sind zyklische Strukturen, dann und nur dann hat ein GC einen echten Vorteil. Aber der ursprüngliche Einwand war, daß man mit RC irgend wo noch eine Referenz auf das Objekt hätte, und so es nicht zerstört würde. Exakt bei so einem Fall bietet der GC keinen Vorteil, da das Objekt nämlich immer noch referenziert wird, und er es ebenfalls nicht zerstören kann!
-
asc schrieb:
Und ist zudem Compilerabhängig. Sofern sich das nicht durch irgendwelche Änderungen an den Sourcen umsetzen lässt, okay. Aber wenn du (wie ich durchaus schon musste) mit mehreren Compilern paralell arbeitest, ist es ein Problem wenn diese die PCH unterschiedlich umsetzen, und die Sourcen ein Compilerabhängiges Include etc. benötigen.
Für gewöhnlich braucht man die PCHs nur während der Entwicklung. Wenn ich z.B. unter MSVC entwickle, habe ich meine PCHs eingeschaltet, da die Frequenz der Compile-Läufe sehr hoch ist.
Andere Compiler (zum Testen) lasse ich für gewöhnlich seltener laufen, z.B. bevor ich meinen Code in die Sourceverwaltung einchecke. Und dieser Compile-Lauf darf dann etwas länger laufen. Bzw. wenn man es richtig machen will, hat man eine Build-Maschine stehen, die selbstständig die Builds für die Compiler laufen lässt. Da ist es mir während der Entwicklung unter MSVC egal wie lange die Builds auf der entfernten Maschine laufen, da ich selbst nicht drauf warten muß. Sind die Builds fehlerhaft, kann mich die Build-Maschine informieren (z.B. per EMail). Auch Runtime-Tests kann man automatisieren.Also weiß ich nicht was da wirklich das Problem ist. Keiner kann mir erzählen, das er alle Compiler während der aktiven Entwicklung testet. Weil das dauert mit oder ohne Templates generell zu lange.
Wenn mehrere Leute in einem Projekte unterschiedliche Compiler zur aktiven Entwicklung benutzen, kann jeder für die PCH-inkludierung selber sorgen. Den MSVC stören ja GCC-PCHs nicht und umgekehrt.
Die Buildtools wie BBv2 (bjam) unterstützt dagegen PCHs compilerneutral. Einmal in das Buildscript aktivieren, den Rest macht das BBv2.
-
HansiHinterseher schrieb:
Wenn mehrere Leute in einem Projekte unterschiedliche Compiler zur aktiven Entwicklung benutzen, kann jeder für die PCH-inkludierung selber sorgen. Den MSVC stören ja GCC-PCHs nicht und umgekehrt.
Ich habe die Compilerkonfiguration (beide älter als der C++ Standard...) nicht mehr im Zugriff, kann auch sein das jemand einfach Mist bei den Einstellungen gemacht hat (Anschließend mussten im anderen Compiler dummy-stdafx.h generiert werden usw.). Und ja, beide Compiler wurden paralell für das Projekt eingesetzt, unterschiedliche Module in dem einen, oder anderen, teilweise aber auch gleiche Codebasis...
Ich muß dazu aber auch sagen, das ich selbst ohnehin kaum mit PCHs arbeite, da ich keine großen Compilezeiten habe (Ich verwende aber auch Techniken wie das Handle-Body Idiom und ähnliches was die Compilezeiten eh schon reduziert).
cu André
-
asc schrieb:
Thema: Typsicherheit. Den im Gegensatz zu den dir genannten C-Casts wird bei Templates der Typ geprüft. Was tatsächlich ein Problem ist, sind die kryptischen Fehlermeldungen, die aber scheinbar nach und nach besser werden (wobei es noch ein langer Weg ist, bis diese auch für einen verständlich sind, der Templates nur am rande verwendet).
Du hast mich nicht verstanden. Bei
template <class T> T GetMax (T a, T b) { T result; result = (a>b)? a : b; return (result); }
wird kein Typ geprueft. T kann alles sein, der Compiler prueft nur, ob das Interface stimmt. Das ist ja fuer mich der Widerspruch zu dem restlichen Konzept von C++. Templates fuehren ein Konzept von z.B. JavaScript in C++ hinein. IMHO ist das dann die Ursache der kryptischen Fehlermeldungen. Der Compiler muss erst bin ins Letzte uebersetzen um am Ende zu merken dass das Interface nicht stimmt oder ein template Typ A nicht mit template Typ B uebereinstimmt, obwohl es so sein muesste.
-
DEvent schrieb:
Der Compiler muss erst bin ins Letzte uebersetzen um am Ende zu merken dass das Interface nicht stimmt oder ein template Typ A nicht mit template Typ B uebereinstimmt, obwohl es so sein muesste.
Hauptsache er merkt es. Soll man dir jetzt den Unterschied zwischen statischer und dynamischer Typprüfung erklären?
-
Bashars primäre Charaterzüge:
+besserwisserisch
+arrogant
+unlustig
-
Ein Template ist kein Type. Eine Instanzierung eines Template schon.
Mit diese Vorlage:
template <class T> T GetMax (T a, T b) { T result; result = (a>b)? a : b; return (result); }
wird durch diese Anwendung:
int main() { GetMax(5,1); }
diese zur Compilezeit erstellt:
int GetMax (int a, int b) { int result; result = (a>b)? a : b; return (result); }
Wo ist die Typenunsicherheit? O.o
-
DEvent schrieb:
Du hast mich nicht verstanden. Bei
template <class T> T GetMax (T a, T b) { T result; result = (a>b)? a : b; return (result); }
wird kein Typ geprueft. T kann alles sein, der Compiler prueft nur, ob das Interface stimmt. Das ist ja fuer mich der Widerspruch zu dem restlichen Konzept von C++. Templates fuehren ein Konzept von z.B. JavaScript in C++ hinein. IMHO ist das dann die Ursache der kryptischen Fehlermeldungen. Der Compiler muss erst bin ins Letzte uebersetzen um am Ende zu merken dass das Interface nicht stimmt oder ein template Typ A nicht mit template Typ B uebereinstimmt, obwohl es so sein muesste.
Entweder verstehe ich dein Posting nicht oder du hast Templates nicht verstanden.
Also, der Reihe nach: Template Typen gibts nicht. T ist als Beispiel ein int. somit ist a und b 100%ig vom gleichen Typ. Steht ja in der GetMax-Signatur!
Nun, was muss T erfüllen? T muß den Operator > implementiert haben. Was z.B. bei int der Fall ist. Kennt int Operator > nicht, wird dir das der Compiler melden.
Heutige Compiler (nein, nicht die von vor 10 Jahren), werden dir recht verständliche Meldungen ausspucken. Die Compiler wurden in dem Bereich weit verbessert.
Ich habe mal dein Beispiel absichtlich fehlerhaft benutzt (anstatt int, mit einer Dummy-Klasse Test die keinen passenden Operator hat). Die Fehlermeldung von MSVC 2005:
test.cpp(18) : error C2676: binary '>' : 'Test' does not define this operator or a conversion to a type acceptable to the predefined operator
test.cpp(25) : see reference to function template instantiation 'T GetMax<Test>(T,T)' being compiled
with
[
T=Test
]Yo, das sollte doch recht unkryptisch sein. Oder?
Für C++0x sind die sogenannten Concepts vorgesehen. D.h. der Template-Entwickler kann explizit die Bedingungen vorgeben. Er kann als Bedingung sagen, T muß Operator > implementiert haben. Wenn nicht, fängt der Compiler erst garnicht an das Template zu kompilieren, und spuckt den Fehler als Bedingung aus. Der User des Templates kann genau ablesen, was erwartet wurde. Ein User selbst braucht aber nicht wissen, wie man Concepts anwendet.
Also auch hier wird sich was in der Zukunft tun.
-
~john schrieb:
~fricky schrieb:
aber nur in seltenen ausnahmen. ein objekt, auf das es keinen verweis mehr gibt, oder objekte die sich gegenseitig referenzieren, aber auf keins davon mehr ein verweis im aktiven code besteht, schmeisst der GC irgendwann automatisch weg.
Du hast den wichtigen Punkt übersehen "auf das es keinen verweis mehr gibt". Wenn diese Bedingung erfüllt ist, wir mit RC das Objekt ebenfalls abgeräumt. Die Ausnahme sind zyklische Strukturen, dann und nur dann hat ein GC einen echten Vorteil. Aber der ursprüngliche Einwand war, daß man mit RC irgend wo noch eine Referenz auf das Objekt hätte, und so es nicht zerstört würde. Exakt bei so einem Fall bietet der GC keinen Vorteil, da das Objekt nämlich immer noch referenziert wird, und er es ebenfalls nicht zerstören kann!
Jo.
Dazu kommt dass GC einen grundsätzlichen und einen effektiven Nachteil hat.
Der grundsätzliche: keine deterministische Finalisierung (wurde sicher schon 100x erwähnt aber egal).
Der effektive (im Sinn von: man hat das Problem mit existierenden Implementierungen, wie z.B. .NET): der GC räumt auch gerne mal Objekte weg die eigentlich noch gebraucht werden, und finalisiert diese auch munter. z.B. Objekte "auf denen" gerade noch eine Member-Funktion ausgeführt wird, einfach deswegen weil diese Member-Funktion das Objekt danach nichtmehr "angreift". Was bei Objekten ohne Finalizer auch egal ist. IMO aber eine sehr dumme Sache wenn man einen Finalizer hat, der z.B. irgendeine unmanaged Resource freigibt, obwohl noch eine native Funktion damit arbeitet. Natürlich kann man dem GC das ausreden, nur kommt es schnell vor dass man irgendwo eine Stelle übersieht wo es nötig gewesen wäre. Und debuggen lassen sich solche Fehler nahezu garnicht.
IMO ein ganz krasser Nachteil von GC Systemen. Betrifft wie gesagt nicht GC grundsätzlich, sondern nur die Implementierungen die das so machen.
-
@HansiHinterseher:
DEvent schreibt immer gerne zum Thema C++, obwohl er C++ weder mag noch sonderlich gut versteht
-
hustbaer schrieb:
@HansiHinterseher:
DEvent schreibt immer gerne zum Thema C++, obwohl er C++ weder mag noch sonderlich gut versteht
So sind sie eben, unsere Linux Fanboys
-
HansiHinterseher schrieb:
Also, der Reihe nach: Template Typen gibts nicht. T ist als Beispiel ein int. somit ist a und b 100%ig vom gleichen Typ. Steht ja in der GetMax-Signatur!
Nun, was muss T erfüllen? T muß den Operator > implementiert haben. Was z.B. bei int der Fall ist. Kennt int Operator > nicht, wird dir das der Compiler melden.
Heutige Compiler (nein, nicht die von vor 10 Jahren), werden dir recht verständliche Meldungen ausspucken. Die Compiler wurden in dem Bereich weit verbessert.
Ich habe auch nichts anderes behauptet. Fuer T kann ich ein int, float oder eben ein String einsetzen. Der Compiler ueberprueft den Typen nicht, sondern nur das Interface. Wenn mein eingesetzter Type eben den operator< nicht implementiert, also das Interface nicht stimmt, dann gibt es ein Fehler. Das ist das gleiche Verhalten wie z.B. in JavaScript.
-
DEvent schrieb:
Das ist das gleiche Verhalten wie z.B. in JavaScript.
Der Unterschied zwischen Compilierzeit- und Laufzeitfehler ist dir bekannt?
-
DEvent schrieb:
Fuer T kann ich ein int, float oder eben ein String einsetzen....Das ist das gleiche Verhalten wie z.B. in JavaScript.
naja, in javascript würde ein stringvergleich wahrscheinlich gehen. dieses c++template würde aber bei
GetMax("hallo","doof")
pointer vergleichen, d.h. für char* braucht man 'ne spezialversion, die 'strcmp' oder sowas benutzt. das wäre eine kleine stolperfalle für anfänger.
-
~fricky schrieb:
naja, in javascript würde ein stringvergleich wahrscheinlich gehen. dieses c++template würde aber bei
GetMax("hallo","doof")
pointer vergleichen, d.h. für char* braucht man 'ne spezialversion, die 'strcmp' oder sowas benutzt. das wäre eine kleine stolperfalle für anfänger.
Wobei man normalerweise davon ausgeht, das std::max nicht mit bekannten Werten aufgerufen wird (Sonst könnte man das ergebnis auch direkt hinschreiben). Sprich, in der Regel sieht es eher so aus (ganz davon abgesehen das strcmp C und nicht C++ ist):
std::string a = "Hallo"; // Initialisierungen stellvertretend für Codeaufrufe std::string b = "Welt"; // zwischendrin std::string ergebnis = std::max(a, b);
Und das liefert das erwartete Erebnis.
-
asc schrieb:
Und das liefert das erwartete Erebnis.
ok, aber
const char *m = std::max("hello", "world")
geht trotzdem nicht, oder täusche ich mich? macht std::max dann auch 'nen pointervergleich?
-
DEvent schrieb:
Ich habe auch nichts anderes behauptet. Fuer T kann ich ein int, float oder eben ein String einsetzen. Der Compiler ueberprueft den Typen nicht, sondern nur das Interface. Wenn mein eingesetzter Type eben den operator< nicht implementiert, also das Interface nicht stimmt, dann gibt es ein Fehler. Das ist das gleiche Verhalten wie z.B. in JavaScript.
Sorry, kenne JavaScript leider nicht. Kann dazu also nichts sagen. Aber bei C++ ist es ein gutes und gewolltes Verhalten, das ich einen Compiler-Error erhalte. Also weiß ich jetzt auch nicht, was dich wirklich daran stört, wenn du sagst "wie in JavaScript".