Programiersprache für Anfänger



  • 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".



  • ~fricky schrieb:

    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?
    🙂

    Das wird so nicht funktionieren, da er ja kein const char* zurück liefert, sondern entsprechend dem impliziten Template-Parameter ein const char[6].
    Hem...



  • HansiHinterseher schrieb:

    ~fricky schrieb:

    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?
    🙂

    Das wird so nicht funktionieren, da er ja kein const char* zurück liefert, sondern entsprechend dem impliziten Template-Parameter ein const char[6].

    dann braucht's wohl doch eine selbstgestrickte variante, wie etwa das:

    template <>
    const char* max(const char* a, const char* b)
    {
        return strcmp(a, b) > 0 ? a : b ;
    }
    

    ^^ausserdem noch in den std-namespace verfrachten.
    🙂



  • HansiHinterseher schrieb:

    ~fricky schrieb:

    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?
    🙂

    Das wird so nicht funktionieren, da er ja kein const char* zurück liefert, sondern entsprechend dem impliziten Template-Parameter ein const char[6].
    Hem...

    Klar geht das:

    const char* i = std::max("aaa", "aaa");
    

    Der Compiler liefert ja auch den Typen, wenn ich fuer i den falschen Typen einsetze:

    test2.cpp:42: error: invalid conversion from 'const char*' to 'int'
    

    Allerdings bezweilfe ich stark, dass der Code das macht, was der Programmierer damit gemeint hat.



  • DEvent schrieb:

    Klar geht das:

    const char* i = std::max("aaa", "aaa");
    

    Der Compiler liefert ja auch den Typen, wenn ich fuer i den falschen Typen einsetze...

    wie jetzt? der eine sagt es geht nicht, der andere sagt, es geht. also was nun?
    🙂



  • Ob es geht hängt wohl vom Compiler ab. Mit MSVC 2005 geht es z.B. nicht.


Anmelden zum Antworten