Programiersprache für Anfänger



  • die sprache java ist langsam weil sie nur interpretiert wird. das muss hier auch mal gesagt werden. die reihenfolge ist so: asm -> c -> c++ -> java -> visual basic. das muss einem anfänger auch klar sein...



  • Eine Sprache kann nicht langsam oder schneller als eine andere sein. Begreift das endlich.



  • Was haben C++ Entwickler eigentlich mit ihren Templates? Ich finde sie absolut sinnlos. So wie ich das sehe sind Templates fuer 2 Sachen gut, zum einen als Typplatzhalter und zum anderen um den Compiler als Taschenrechner zu misbrauchen. Die Rolle der Typplatzhalter ist in einer stark typesierten Sprache irgendwie seltsam und um etwas auszurechnen brauche ich den Compiler nicht.

    Wieso forciert der Compiler die Typen so strikt, const-correctness, dynamic_cast und static_cast anstelle von (int)x und (foo*)x, printf() ist boese, usw. Aber auf der anderen Seite kann ich einer Funktion template <class T> T max(T a, T b) {} alles moegliche uebergeben, eine String-Klasse, eine Hashmap, int, float, char. Klar beschwert sich der Compiler nach 10min uebersetzen, dass das Interface falsch ist und liefert mir eine 10 Zeilen lange Fehlermeldung. Aber wieso kann man dann nicht gleich den Typen eingrenzen?



  • Nun als Hobbyprogrammierer, der mit C# angefangen und nun hauptsächlich mit C++ weitergemacht hat will ich mal aus meiner bescheidenen Erfahrung sprechen:
    1. Immer wenn jemand als Vorteil von C++ gegenüber C# oder Java den Performancevorteil nennt will ich gegen die Wand springen.. Das mag für manche Projekte zutreffen, aber für die breite Masse nicht. Wenn ihr euch ständig Gedanken über die Performance macht geht doch Maschienencode schreiben.
    2. Das was mir an C++ gefällt ist, dass so viele Dinge erlaubt werden. Ich habe dadurch auch viele Dinge gelernt und meinen Horizont in Richtung objektorientierter bzw. multiparadigmischer Sprachen stark erweitert. Viele Dinge, die z.B. oft geraten werden erscheinen aber perfektionistisch(auch wenn es die Syntax nicht ist) und in der Praxis zahlt es sich oft nicht aus. Ich denke auch, dass das größte Problem von C++ der Mangel an einheitlichen guten Bibliotheken ist(Die Standardbibliothek und Boost haben zwar eine sehr gute Qualtität, aber wie siehts mit GUI aus? Da gibts nix.) und man braucht oft ein wenig mehr Code um das selbe zu erreichen, weswegen Javaprojekte wohl schneller fertig werden.
    3. Der Grund warum ich hauptsächlich C++ benutze ist, das meine Projekte zwar keine Spiele sind, aber meistens etwas damit zu tun haben und da kommt für mich Java eigtl. weniger in Frage. XNA kann man unter Linux vergessen, also -> C++

    Aus Programmierersicht mag es wieder anders aussehen ;p

    http://xkcd.com/303/



  • DEvent schrieb:

    Was haben C++ Entwickler eigentlich mit ihren Templates? Ich finde sie absolut sinnlos.

    Das sagt jetzt viel über Dich und wenig über Templates aus. Aber wie wäre es mit Ada? Es gibt in Ada ebenfalls Generics, dafür in einer weniger verwirrenden Syntax.

    DEvent schrieb:

    Aber wieso kann man dann nicht gleich den Typen eingrenzen?

    Das ist ein altes bekanntes Problem von C++ Templates, und die dabei auftretenden Fehlermeldungen sind zu Recht berüchtigt. Deshalb wird die nächste ISO Norm eine Lösung beinhalten, die es erlaubt gleich Fehlermeldungen bei Übergabe eines ungeeigneten Typs auszugeben.



  • DEvent schrieb:

    Was haben C++ Entwickler eigentlich mit ihren Templates? Ich finde sie absolut sinnlos. So wie ich das sehe sind Templates fuer 2 Sachen gut, zum einen als Typplatzhalter und zum anderen um den Compiler als Taschenrechner zu misbrauchen. Die Rolle der Typplatzhalter ist in einer stark typesierten Sprache irgendwie seltsam...

    Das ist auch die Ansicht von vielen, die C++ nur an der Oberfläche kennen, oder nur aus der Anfangszeit der Templates. Und Typplatzhalter machen gerade in einer stark typisierten Sprache Sinn, um Typsichere Container etc. verwenden zu können und Code besser wiederverwerten zu können.

    Was können C++ Templates aber noch, was über reine Typersetzungen hinaus geht?
    a) Allgemeine Behandlungen mit der gleichen Syntax wiederverwerten, obwohl die Typen gänzlich unterschiedlich sind (z.B. Value/Pointer/Referenz); Thema: Templatespezialisierung
    b) Verhalten mit Änderung eines Parameters den Umständen anpassen (z.B. Smartpointer die sich über einen Templateparameter so umschalten lassen das Beispielsweise statt new/delete das COM-Modell [mit Release usw.] unterstützt wird) und dennoch sonst die gleiche Syntax erlauben (Der Smartpointer verhält sich nach außen genau so wie er es mit new/delete gemacht hätte); Thema: Policy-Klassen
    c) Verhalten bei Vererbung in Abhängigkeit der abgeleiteten Klasse umsetzen; Thema: curiously recurring template pattern
    d) Mittels oben genannten Punkten und der von dir belächelten Templatemetaprogrammierung können Dinge wie generische Funktionszeiger umgesetzt werden, unabhängig davon ob die "Funktion" in Realität eine freie Funktion, Klassenmethode oder gar ein Funktionsobjekt ist...

    Und vieles mehr.

    DEvent schrieb:

    Wieso forciert der Compiler die Typen so strikt, const-correctness, dynamic_cast und static_cast anstelle von (int)x und (foo*)x, printf() ist boese, usw. Aber auf der anderen Seite kann ich einer Funktion template <class T> T max(T a, T b) {} alles moegliche uebergeben,...

    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).

    Und was die Compilezeit angeht: Wir verwenden Templates in unserer Anwendung, und ja, es hat etwas die Compilezeit erhöht, aber bei weiten nicht in den Ausmaßen die du hier annimmst. Dies sieht in Projekten mit intensiver Nutzung der Templatemetaprogrammierung sicher anders aus, aber in einen 0815 Durchschnittsprojekt sind die Compilezeiten nicht so hoch als das man wirklich lange Kaffeepausen machen könnte. 😉

    Zudem sollte man Projekte eh ab einer gewissen Größe modularisieren.

    cu André



  • 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 😃


Anmelden zum Antworten