schönes c++?



  • Hallo,

    Ich bin schon länger auf der Suche nach einer für mich passenden Sprache. Ich komme aus dem Interpretersprachen- und Javaumfeld. Ich würde mich aber gerne nochmal mit einer compilierbaren Sprache beschäftigen, die auch einen gewissen "Elegantheits- und Schönheitsanspruch" erfüllt.
    Ich hab mir mal D etwas genauer angesehen. Scheint schön konsistent zu sein, mir gefällt aber nicht, dass die Community so klein ist und man letztlich nicht weiß, ob D Zukunft hat.
    Ich möchte mich deswegen nochmal mit C++ beschäftigen. C++ hat ja bekannte Schwächen, aber auch offenbar funktionierende Workarounds dafür. Da man mit C++ viel - und damit auch viel Mist - anstellen kann, ist es offenbar notwendig, gewisse Standards einzuhalten und gewisse Libraries zu nutzen, um guten(TM) Code zu schreiben.

    Meine Frage hier nun:
    Welche Standards und welche Libraries sind das?

    Genauer:
    In Java gibts einen GC. Welche Alternativen (außer manuelle Speicherverwaltung) gibts für C++?
    In Java gibts keine Pointer sondern Referenzen. Wie vermeide ich Pointer-Arithmetik in C++?
    In Java gibts das gut anerkannte JavaDoc. Was ist gang und Gäbe in C++?
    Welche Möglichkeiten gibt es, die Beschäftigung mit Header-Dateien zu vermeiden (imho sind Header redundant)?
    Wie realisiert man auf elegante Art Threads?
    Wie organisiere ich ordentlich ein Projekt?
    Gibt es vielleicht sogar ein C++Subset, welches nur die "sicheren" Features von C++ zulässt?

    Vielleicht kennt ihr tolle Artikel im Netz, die über solche "Best Practices" informieren?

    Ich habe irgendwo mal ein imho tolles Programmierer-Motto gelesen: "Dont make me think!" Ich würde also gerne C++ so programmieren, dass ich meine Aufmerksamkeit nicht auf die C++Fallstricke verschwenden muss.

    Danke für Eure Hilfe.....



  • musiknase schrieb:

    Meine Frage hier nun:
    Welche Standards und welche Libraries sind das?

    Der C++-Standard und die C++-Standardbibliothek. 😉

    musiknase schrieb:

    In Java gibts einen GC. Welche Alternativen (außer manuelle Speicherverwaltung) gibts für C++?

    Fertige Klassen, die RAII (eine Technik zur automatischen Verwaltung von Ressourcen) nutzen. Zum Beispiel STL-Container.

    musiknase schrieb:

    In Java gibts keine Pointer sondern Referenzen. Wie vermeide ich Pointer-Arithmetik in C++?

    Indem du sie nicht benutzt?

    musiknase schrieb:

    In Java gibts das gut anerkannte JavaDoc. Was ist gang und Gäbe in C++?

    Da gibts nicht unbedingt einen einzigen Standard. Als Dokumentationssystem wird z.B. häufig Doxygen verwendet.

    musiknase schrieb:

    Welche Möglichkeiten gibt es, die Beschäftigung mit Header-Dateien zu vermeiden (imho sind Header redundant)?

    Keine. Wieso sind sie redundant? Weil man sie in Java nicht hat? C++ geht eben einen anderen Weg.

    musiknase schrieb:

    Wie realisiert man auf elegante Art Threads?

    Z.B. mit Boost.Thread oder den Threads von SFML.

    musiknase schrieb:

    Wie organisiere ich ordentlich ein Projekt?

    Im Wesentlichen Auftrennung der Klassen in Schnittstelle (Header) und Implementierung (.cpp-Datei). Aber dazu kann man sehr vieles sagen...

    musiknase schrieb:

    Gibt es vielleicht sogar ein C++Subset, welches nur die "sicheren" Features von C++ zulässt?

    Benutze doch einfach nur die sicheren Features. Ab und zu wirst du auch "gefährliche" Dinge nutzen müssen, aber wenn du dich mit ihnen befasst, ist das kein Problem.

    musiknase schrieb:

    Vielleicht kennt ihr tolle Artikel im Netz, die über solche "Best Practices" informieren?

    Auch hier gibt es sehr viele Informationen. Ich denke, das beste ist vorerst, du schaust ein gutes C++-Anfängerbuch an (wie den C++-Primer), dann wird auch auf solche Dinge hingewiesen. Mit der Zeit kannst du weiterführende Literatur von Scott Meyers, Herb Sutter etc. lesen.

    musiknase schrieb:

    Ich habe irgendwo mal ein imho tolles Programmierer-Motto gelesen: "Dont make me think!" Ich würde also gerne C++ so programmieren, dass ich meine Aufmerksamkeit nicht auf die C++Fallstricke verschwenden muss.

    Im Allgemeinen musst du das nicht, verwende einfach die C++-Mittel, die für eine entsprechende Aufgabe vorgesehen sind. Vermeide es besonders am Anfang, fragwürdig designte Bibliotheken (z.B. für GUI) zu verwenden, um dir nicht einen merkwürdigen Codestil anzugewöhnen.

    Aber eine grundlegende Frage: Warum willst du Java in C++ programmieren? Das hat keinen Sinn und führt nur zur Frustration. Du solltest von Grund auf neu an eine Programmiersprache herangehen, die Konzepte und die Philosophie von C++ unterscheiden sich wesentlich von anderen Sprachen. Es ist für dich das beste, wenn du nicht versuchst, Dinge aus Java 1:1 übertragen. Dafür lernst du auch neue Konzepte wie z.B. Templates kennen. Also geh unvoreingenommen an die Sache ran! 🙂

    Ach ja, es wird hier im Thread wahrscheinlich Leute geben, die versuchen, C++ als hässliche, unsichere, mühsame und komplizierte Sprache darzustellen. Du wirst relativ schnell merken, dass sie eine fundamentale Abneigung besitzen und es ihnen nur ums Flamen geht. Schenke ihnen nicht unnötige Beachtung.



  • In Java gibts einen GC. Welche Alternativen (außer manuelle Speicherverwaltung) gibts für C++?

    Durch Einhaltung von RAII musst du dich kaum mehr um Speicherverwaltung kümmern. Durch new erzeugte Objekte sollten bis auf Ausnahmen in einen shared_ptr verpackt werden (shared_ptr ist Teil von boost).

    In Java gibts keine Pointer sondern Referenzen. Wie vermeide ich Pointer-Arithmetik in C++?

    Durch Einsetzen von Iteratoren, wobei die nicht immer gegen Ausübung von Unfug schützen (so wie *(myVector.begin()+x)). Ist in der Praxis aber eher kein Problem, wenn man schon etwas allgemeine Programmiererfahrung mitbringt.

    In Java gibts das gut anerkannte JavaDoc. Was ist gang und Gäbe in C++?

    Die Dokumentationen der verwendeten Bibliotheken, also zuerst mal http://www.cppreference.com/wiki/ für die Standardbibliothek und http://www.boost.org/doc/ für boost.

    Welche Möglichkeiten gibt es, die Beschäftigung mit Header-Dateien zu vermeiden (imho sind Header redundant)?

    Je nachdem kann man den ganzen Code im Header belassen, das sorgt auch dafür, dass der Compiler absolut alles inlinen kann, wenn ihm das sinnvoll erscheint. Sieh dir boost an, dort ist fast alles header-only. In manchen Fällen geht es allerdings nicht, bzw. ist nicht sinnvoll. Änderungen an den Headern führt ja dazu, dass alle abhängigen Übersetzungseinheiten neukompiliert werden müssen.



  • Nanyuki schrieb:

    Durch new erzeugte Objekte sollten bis auf Ausnahmen in einen shared_ptr verpackt werden (shared_ptr ist Teil von boost).

    Auf keinen Fall! Ein shared_ptr ist nur nötig, wenn sich mehrere Objekte einen Besitz teilen und der letzte für die Freigabe verantwortlich sein soll. Und das ist eher die Ausnahme, im Allgemeinen ergibt sich durch das Design eindeutig, wer für die Speicherverwaltung zuständig ist. Oft braucht man gar keine dynamische Speicheranforderung. Oder man nimmt Smart-Pointer, die für den Fall angebracht sind, z.B. boost::scoped_ptr oder std::auto_ptr .

    Ich würde von dem Gedanken wegkommen, einen Garbage-Collector in C++ nachbauen zu wollen -- shared_ptr überall zu verwenden scheint mir so ein verzweifelter Versuch zu sein. Manuelle Speicherverwaltung kann auch auf ein Minimum beschränkt werden, ohne dass man einen (Pseudo-)GC benutzt.

    Nanyuki schrieb:

    Je nachdem kann man den ganzen Code im Header belassen, das sorgt auch dafür, dass der Compiler absolut alles inlinen kann, wenn ihm das sinnvoll erscheint.

    Moderne Compiler wie der von Visual Studio können das auch, wenn sich Code in Implementierungsdateien befindet.

    Nanyuki schrieb:

    Sieh dir boost an, dort ist fast alles header-only. In manchen Fällen geht es allerdings nicht, bzw. ist nicht sinnvoll. Änderungen an den Headern führt ja dazu, dass alle abhängigen Übersetzungseinheiten neukompiliert werden müssen.

    Für Templatedefinitionen ist es unbestritten sinnvoll. Ansonsten würde ich wie du sagst vorsichtig sein, da man schnell sehr lange Kompilierzeiten riskiert, wenn man sich bei der Codestrukturierung zu wenig überlegt (dazu gehören Header, die Definitionen oder #include -Statements nur aus Bequemlichkeitsgründen enthalten).



  • Nexus schrieb:

    Auf keinen Fall! Ein shared_ptr ist nur nötig, wenn sich mehrere Objekte einen Besitz teilen und der letzte für die Freigabe verantwortlich sein soll. Und das ist eher die Ausnahme, im Allgemeinen ergibt sich durch das Design eindeutig, wer für die Speicherverwaltung zuständig ist. Oft braucht man gar keine dynamische Speicheranforderung. Oder man nimmt Smart-Pointer, die für den Fall angebracht sind, z.B. boost::scoped_ptr oder std::auto_ptr .

    Ich würde von dem Gedanken wegkommen, einen Garbage-Collector in C++ nachbauen zu wollen -- shared_ptr überall zu verwenden scheint mir so ein verzweifelter Versuch zu sein. Manuelle Speicherverwaltung kann auch auf ein Minimum beschränkt werden, ohne dass man einen (Pseudo-)GC benutzt.

    Ja, ich habe mich etwas unglücklich ausgedrückt. Wenn ich mir so meinen Code anschaue, dann wandern viele mit new erzeugte Objekte sofort in einen Container, der sich fortan um die Speicherverwaltung kümmert. Oder ein mit new erzeugtes Objekt soll etwas später an eine Funktion übergeben werden, zwischendurch kann die Funktion aber verlassen werden (hier ist wohl auto_ptr angebrachter). shared_ptr setze ich dann ein, wenn teuer zu kopierende Objekte von Funktionen zurückgegeben werden.

    Nexus schrieb:

    Moderne Compiler wie der von Visual Studio können das auch, wenn sich Code in Implementierungsdateien befindet.

    Stimmt, aber ich glaube, dass der GCC das erst in der kommenden Version lernen wird.

    Nanyuki schrieb:

    Für Templatedefinitionen ist es unbestritten sinnvoll. Ansonsten würde ich wie du sagst vorsichtig sein, da man schnell sehr lange Kompilierzeiten riskiert, wenn man sich bei der Codestrukturierung zu wenig überlegt (dazu gehören Header, die Definitionen oder #include -Statements nur aus Bequemlichkeitsgründen enthalten).

    Ja, sicher. Ich halte auch nicht viel davon, die Header unnötig zu überfrachten, zumal ich noch eine Single-Core-Maschine habe und damit das Kompilieren ewig dauert. Aber gerade wenn Funktionen zumindest teilweise mit konstanten Parametern aufgerufen werden, können die Laufzeitersparnisse enorm sein, wenn der Compiler inlinen kann.



  • Und Vorsicht, Exception safety und copy assignment operator sind schlimmstes C++ Bashing und wird sofort von volkard gelöscht.



  • Nanyuki schrieb:

    Ja, ich habe mich etwas unglücklich ausgedrückt. Wenn ich mir so meinen Code anschaue, dann wandern viele mit new erzeugte Objekte sofort in einen Container, der sich fortan um die Speicherverwaltung kümmert.

    Genau, das mache ich ähnlich. Rohe besitzende Zeiger versuche ich meistens zu kapseln oder an ungefährlichen Stellen (z.B. einfache Klasse, die sicher keine Exceptions wirft) zu haben.

    Nanyuki schrieb:

    shared_ptr setze ich dann ein, wenn teuer zu kopierende Objekte von Funktionen zurückgegeben werden.

    Das ist für mich eher einer der wichtigsten Anwendungsbereiche für auto_ptr ; wenn die Funktion nur eine Factory-Aufgabe hat, kann man damit schön sichere Move-Semantik implementieren.

    avrül schrieb:

    Und Vorsicht, Exception safety und copy assignment operator sind schlimmstes C++ Bashing und wird sofort von volkard gelöscht.

    Mich würde wirklich mal interessieren, was du gesagt hast. 🙂
    Exceptionsicherheit ist in der Tat kein triviales Unterfangen, durch RAII kann allerdings viel vereinfacht werden. Sie besteht aber nicht nur aus korrektem Freigeben, je nach Situation soll beispielsweise ein Rollback durchgeführt werden oder ein Status konsistent gehalten werden. Mit dieser Gegebenheit muss man sich übrigens nicht nur in C++ beschäftigen.



  • > Mich würde wirklich mal interessieren, was du gesagt hast. 🙂

    Nichts, was mit fricky mithalten könnte. 🙂
    Ich erinnere mich dunkel, er meinte, dass "C++ für Exceptions zu kompliziert sei" oder so. Hab's mir leider nicht gemerkt.



  • Ad aCTa schrieb:

    Nichts, was mit fricky mithalten könnte. 🙂
    Ich erinnere mich dunkel, er meinte, dass "C++ für Exceptions zu kompliziert sei" oder so. Hab's mir leider nicht gemerkt.

    Interessant. Ja, war auch meine Vermutung im anderen Thread. Naja, so muss man sich nicht gerade wundern. 😉



  • musiknase schrieb:

    Vielleicht kennt ihr tolle Artikel im Netz, die über solche "Best Practices" informieren?

    die wichtigsten best practices wären etwa diese hier: http://yosefk.com/c++fqa/why.html
    🙂



  • Nexus schrieb:

    avrül schrieb:

    Und Vorsicht, Exception safety und copy assignment operator sind schlimmstes C++ Bashing und wird sofort von volkard gelöscht.

    Mich würde wirklich mal interessieren, was du gesagt hast. 🙂
    Exceptionsicherheit ist in der Tat kein triviales Unterfangen, durch RAII kann allerdings viel vereinfacht werden. Sie besteht aber nicht nur aus korrektem Freigeben, je nach Situation soll beispielsweise ein Rollback durchgeführt werden oder ein Status konsistent gehalten werden. Mit dieser Gegebenheit muss man sich übrigens nicht nur in C++ beschäftigen.

    Und in C++ hast du eben einige Sachen mehr die man schnell falsch macht, die es aber sonst in (fast) keiner Sprache gibt, z.B. copy assignment operator.

    Und auf

    hustbaer schrieb:

    avrül schrieb:

    ➡ Exceptions in c++ sind zu kompliziert

    was hättest du denn gern einfacher?

    Hab ich sowas ähnliches geantwortet: Man müsste wohl eher sagen, C++ ist zu kompliziert für Exceptions. Man muss sich nur mal anschauen, was alles über Exception safety und copy assignment operator geschrieben wurde.



  • Na und? Low-Level tut immer an mancher Stelle etwas weh, C++ ist lowlevel ----> C++ kann manchmal wehtun, musss es aber nicht. Es hindert dich niemand daran, Exception-Safety-Probleme zu abstrahieren (RAII/pImpl/Exceptionfree swap), das macht die Sprache eben attraktiv. (:



  • Ad aCTa schrieb:

    ...Exceptionfree swap

    was ist denn damit gemeint?
    🙂



  • ;fricky schrieb:

    Ad aCTa schrieb:

    ...Exceptionfree swap

    was ist denn damit gemeint?
    🙂

    wenns dich wirklich interessiert, dann suchs dir doch selber raus. da du dich aber garnicht für c++ interessierst, könntest du auch einfach aufhören in c++ threads rumzutrollen.



  • hustbaer schrieb:

    ;fricky schrieb:

    Ad aCTa schrieb:

    ...Exceptionfree swap

    was ist denn damit gemeint?
    🙂

    wenns dich wirklich interessiert, dann suchs dir doch selber raus.

    hab ich versucht. eigentlich bin ich ein meister im googlen, aber irgendwie finde ich den begriff nicht.
    🙂



  • @;fricky
    "Exception safe swap"
    oder
    "non-throwing swap"
    ist damit gemeint

    @avrül
    Exception-safety ist in (fast) allen Sprachen mit Exceptions ein Problem. Nur wird es da eben oft ignoriert.

    (Persönlich verstehe ich eh nicht, warum die ganzen modernen Skriptsprachen nicht das Exceptionsystem aus Common Lisp kopieren. Da kann man bei jeder Condition, nämlich mögliche Restarts definieren.)



  • ;fricky schrieb:

    eigentlich bin ich ein meister im googlen, aber irgendwie finde ich den begriff nicht.

    gemeint ist wohl das, was im fünften von "c++ Exception free swap" angesprochen wird.
    http://forums.devarticles.com/c-c-help-52/using-swap-to-make-assignment-operator-exception-safe-131249.html?p=178923

    http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Copy-and-swap

    Und jetzt kommts endlich.
    http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-throwing_swap



  • @volkard
    oh, More C++ Idioms schaut eh sehr interessant aus. Danke für den Link 🙂



  • rüdiger schrieb:

    @avrül
    Exception-safety ist in (fast) allen Sprachen mit Exceptions ein Problem. Nur wird es da eben oft ignoriert.

    In (fast) allen anderen Sprachen kann man keine copy assignment operatoren überschreiben, also schon mal eine Fehlerquelle weniger. Die meisten anderen Sprachen die Exceptions haben, haben auch einen GC und damit muss man schon mal nicht darüber nachdenken, ob man auch bei ner Exception allen Speicher wieder frei gibt. Und ja, ich weiß, in C++ haben wir doch auto und shared und smart und weak und ... pointer für sowas und das ist doch die Kompl... äähh Schönheit von c++ das wir uns immer wieder den passenden Pointer aussuchen könnten ...



  • rüdi, volkard: danke, das hätte ich allein nie gefunden.
    wenn ich's richtig verstanden habe, will man mit solchen verrenkungen verhindern, dass eine swap-funktion einem die objekte zersemmelt, wenn sie durch eine exception abbricht. klingt für mich nach einem der typischen c++ workarounds, also nichts, was allgemeingültigkeit hat (hätte ja sein können).
    🙂



  • nachtrag: warum nicht etwa so?

    void swap (object *a, object *b)
    {
       char *p = (char*)a;
       char *q = (char*)b;
       int s;
       for (s=0; s<izeof(object); s++)
       {
          p[s] = p[s] ^ q[s];
          q[s] = p[s] ^ q[s];
          p[s] = p[s] ^ q[s];
       }
    }
    

    ^^XOR-swap, dürfte keine exception triggern, weil z.b. kein temporärer speicher alloziert werden muss.
    🙂


Anmelden zum Antworten