C++ VS Java ft. C#: To RAII or not to RAII



  • Hallöchen zusammen,

    Wir wissen doch alle, dass die typische Frage "Was ist denn die beste Programmiersprache" nicht objektiv zu beantworten ist.

    Mich würde aber interessieren "Was ist das Beste an dieser Programmiersprache" und welche Dinge sollte man vermeiden, weil sie zu schlechtem Code führen (können), z.B. unleserlich, kompliziert, schwer zu warten/erweitern. Schließlich hat C++ ja viele verschiedene Bestandteile.

    Mal schauen, obs was wird, oder ob das hier als sinnlos empfunden wird.

    Ich fang mal an (Ich werde die Liste aktualisieren, es dürfen gerne Bemerkungen dazu gemacht werden):

    [Gut]
    - RAII (!)

    • const

    [Vermeiden]
    - naked new and delete



  • [Schlecht, aber alternativlos]
    iostreams

    [Immer vermeiden]
    shared_ptr<non-const>
    list<>
    uniform initialization



  • alternativlos schrieb:

    [Immer vermeiden]
    uniform initialization

    Nur wenn man nicht weiß, wann man sie falsch verwendet 😉



  • alternativlos schrieb:

    [Immer vermeiden]
    shared_ptr<non-const>

    ? Hä, weil man sonst nen Mutex oder eine atomare Operation verwenden muss oder wie ist das gemeint?



  • Ohne jetzt einen rießen Krieg auslösen zu wollen:

    Was genau begeistert Euch eigentlich an C++ so sehr, dass ihr den ganzen Mehr-Aufwand was eventuelle Risiken (leaks, zB) und die ganzen, wirklich komplexen Design-Fragen auf Euch nehmt?

    Wenn man jetzt z.B Java programmiert, dann ist das ganze "wie mache ich es jetzt" etc. rein bezogen auf das, was man wirklich umsetzen will und nicht darauf, wie genau man die Sprache jetzt verwendet, um das zu erreichen.

    Im Endeffekt ist es viel simpler und man macht sich mehr Gedanken um die Funktionalität der Software als die Sprache.

    Ich will jetzt keinesfalls sagen, dass einer der beiden Sprachen besser ist als die andere, mich interessiert lediglich ernsthaft, was Euch an C++ so gut gefällt. Findet ihr, man kann durch den frei wählbaren Stil schönere Programme schreiben? Effizientere? Oder macht es einfach Spaß, mit der STL oder was auch immer verrückte Konstrukte aufzustellen?
    Seht ihr einen echten Vorteil oder ist es lediglich Euer persönlicher Geschmack?


  • Mod

    Ich will jetzt keinesfalls sagen, dass einer der beiden Sprachen besser ist als die andere, mich interessiert lediglich ernsthaft, was Euch an C++ so gut gefällt. Findet ihr, man kann durch den frei wählbaren Stil schönere Programme schreiben? Effizientere? Oder macht es einfach Spaß, mit der STL oder was auch immer verrückte Konstrukte aufzustellen?
    Seht ihr einen echten Vorteil oder ist es lediglich Euer persönlicher Geschmack?

    lol



  • 5cript schrieb:

    alternativlos schrieb:

    [Immer vermeiden]
    uniform initialization

    Nur wenn man nicht weiß, wann man sie falsch verwendet

    Die Fälle, in denen es tatsächlich sinnvoll wäre, sind mir nie vorgekommen.

    Ruvi schrieb:

    alternativlos schrieb:

    [Immer vermeiden]
    shared_ptr<non-const>

    ? Hä, weil man sonst nen Mutex oder eine atomare Operation verwenden muss oder wie ist das gemeint?

    Das wäre eine notwendige Vorsichtsmassnahme. Hast du ein Beispiel, bei dem das auftritt?



  • Arcoth schrieb:

    lol

    Ist die Frage wirklich so unglaublich unbeantwortbar?

    Ich habe weder Präferenzen für die eine noch die andere Sprache, noch will ich irgendwelche wirklich vertreten.

    Es fiel mir nur auf, dass man sich um einige Dinge in (beispielsweise) Java weniger Gedanken machen muss, ohne einen Nachteil zu haben.



  • hm schrieb:

    Es fiel mir nur auf, dass man sich um einige Dinge in (beispielsweise) Java weniger Gedanken machen muss, ohne einen Nachteil zu haben.

    Man muss sich in C++ auch keine Gedanken um Speicherverwaltung machen, das ist ein Mythos! Destruktoren ermöglichen keinerlei Leaks jeglicher Art und sind wesentlicher besser als GC, der sich nur um Speicher kümmert.



  • Ich hatte letztens ein Projekt in Java und mehrfach das Problem, einen Container mit einem Prädikat zu durchsuchen. Sowas gibts bei Java in der Standardbibliothek einfach nicht.
    Im Allgemeinen hatte ich oft das Gefühl, dass ich in Java deutlich mehr Code schreiben muss als für eine vergleichbare Funktionalität in C++.



  • alternativlos schrieb:

    Das wäre eine notwendige Vorsichtsmassnahme. Hast du ein Beispiel, bei dem das auftritt?

    Notwendig nur wenn auch mehrere Threads involviert sind. Mich auch erstmal deine Begründung dafür interessieren, weshalb Shared Pointer auf nicht-Konstante Objekte eine schlechte Idee sind. ich lasse mich gerne überzeugen, aber einfach so hinnehmen kann ich die Aussage nicht, wenn ich nicht weiss warum.

    Ich sehe ein dass es Sinn macht das Objekt const zu machen, dass wenn alle nur lesen. Aber das ist nicht immer der Fall.



  • hm schrieb:

    Arcoth schrieb:

    lol

    Ist die Frage wirklich so unglaublich unbeantwortbar?
    [...]
    Es fiel mir nur auf, dass man sich um einige Dinge in (beispielsweise) Java weniger Gedanken machen muss, ohne einen Nachteil zu haben.

    In Java werden Dir Indirektionen aufgezwungen (fast alles sind Referenzen) und Du hast auch sonst kaum Kontrolle beim Speicherlayout. Speicherlayout ist heutzutage wichtiger denn je, denn so ein 2nd-Level-Cache-Miss kostet richtig viele Zyklen heutzutage. In C++ gibt es nur Indirektionen wenn du explizit danach fragst. Java Generics sind sehr schwach im Vergleich zu dem, was Dir C++ mit Templates bietet. Java Generics basieren auf Type Erasure und vom Compiler eingefügte Casts. C++ Templates funktionieren anders: "Monomorphisation". Dabei wird keine Typinformation weggeschmissen und es lässt sich alles besser optimieren. Wenn Du z.B. std::sort auf ein Array bestehend aus Dingen eines eigenen Typs mit einem benutzerdefinierten Vergleichsfunktor loslässt, dann wird eine spezielle std::sort-Funktion übersetzt, die genauso gut wie die handgeschriebene Version wäre. Deswegen spricht man im C++ Kontext auch von "zero cost abstraction", was 'ne ziemlich geniale Sache ist.

    Wenn Du 'ne Zeit lang mit C++ gearbeitet hast und so langsam ein Gefühl dafür bekommen hast, wie du die Sprachmittel effektiv einsetzen kannst, dann wirst Du die Programmiersprachenlandschaft mit anderen Augen sehen. So war's bei mir. Ich hab im Studium hauptsächlich Java programmiert und danach C++ angefangen, was jetzt auch schon wieder 8 Jahre her ist.

    Bad und ugly? Ja, gibt's natürlich auch. Es gibt viele Aspekte an C++, die ich scheiße finde, sowohl syntaktisch als auch semantisch. Der "Erfinder" Stroustrup sagte mal "Within C++, there is a much smaller and cleaner language struggling to get out.". Die Sprache verbessert sich in der Hinsicht von Version zu Version. Ich freu' mich schon auf "concepts lite" und "modules". Concepts lite werden diese "SFINAE-Template-Trickserei" ersetzen, die für Anfänger wahrscheinlich wie Hyroglyphen aussahen. Und mit "modules" werde ich hoffentlich diese lästigen Headerfiles los. Diese Redundanz zwischen Deklaration und Definition nervt mich einfach.

    Wer wissen will, wie 'ne Programmiersprache aussehen kann, die die guten Dinge von C++ behält, vereinfacht und mit Features aus der ML-Sprachfamilie (algebraische Datentypen, Pattern Matching) sowie mit einer eigenen Version von "region pointers" aus Cyclone vereint und dadurch sicherer und angenehmer wird, sollte sich mal Rust angucken. Als ich C++ gelernt hatte, fand ich dann Java eher blöd. Als ich Rust gelernt hatte, fand ich dann C++ eher blöd. 😃 SCNR!



  • Nathan schrieb:

    Man muss sich in C++ auch keine Gedanken um Speicherverwaltung machen, das ist ein Mythos! Destruktoren ermöglichen keinerlei Leaks jeglicher Art und sind wesentlicher besser als GC, der sich nur um Speicher kümmert.

    Du hast Recht, wenn man sich an das RAII Prinzip hält, dann deckt man vermutlich einen Großteil ab.
    Aber deckt man alle Fälle ab? Gibt es nicht trotzdem einige Fälle, in denen man doch ziemlich Hirnschmalz reinstecken muss? Exceptions, multithreading, sowas eventuell?

    Wie sieht's eigentlich aus mit der Frage ob man etwas auf dem Stack oder dem Heap anlegt? Da ich nie wirklich produktiv C++ programmiert habe, weiß ich gar nicht, wie man das abwägt?

    Allgemein sieht man hier im Forum halt immer wieder ziemlich gigantische Konstrukte, die irgendeiner mit viel Liebe zusammen gebastelt hat und wenn man die Sprache (C++) nicht wirklich verdammt gut kann, dann braucht man eine Weile, bis man das entwirrt hat und etwa versteht, wie genau es arbeitet.



  • hm schrieb:

    Es fiel mir nur auf, dass man sich um einige Dinge in (beispielsweise) Java weniger Gedanken machen muss, ohne einen Nachteil zu haben.

    Na dann musst du schon beispiele bringen.

    @Topic (achtung, eigene meinung):

    [Gut]
    -Schnell
    -Kurzer code
    -RAII
    -Lambdas!
    -Kompatibilität zu C

    [Schlecht]
    -Headersystem, keine module
    -Template fehlermeldungen (da keine concepts)
    -Keine reflection
    -Sehr überschaubare standardlib
    -Viele problematische hacks (0-terminierte strings, enable_if etc)
    -Alles mit präprozessor
    -Kompatibilität zu C



  • krümelkacker schrieb:

    [...]

    Das ist doch mal ein sehr interessanter Post, dankeschön 🙂

    Die Dinge klingen für mich theoretisch alle sehr nachvollziehbar, durch meine mangelnde Erfahrung im Beruf allerdings nicht wirklich konkret vorstellbar.

    Ist vermutlich auch Projekt-abhängig. Momentan eher im Webbereich mit Java und Spring unterwegs.
    Da ist nun mal nichts komplexes dabei. Man zieht seine MVC Struktur auf und die bisschen Logik, die es an diverse Stellen noch zu implementieren gibt ist auch nie so wirklich komplex.

    Eventuell krieg ich ja in meinem Berufsleben irgendwann mal die Möglichkeit, an einem richtigen C++ Projekt mitzuarbeiten. Vielleicht geht mir dann ein Lichtlein auf.
    Sofern hab ich halt eigentlich nur Bücher (Meyers) gelesen. In denen wird schnell klar, dass die Sprache wirklich elegant sein kann, aber so wirklich "das muss man haben!" Gefühl kam nie auf.

    Sowas wie die Annotationen in Java find ich zB auch sehr schön. Ist halt sehr abstrahiert. Weiß gar nicht, ob es ähnliches in C++ gibt.



  • hm schrieb:

    Gibt es nicht trotzdem einige Fälle, in denen man doch ziemlich Hirnschmalz reinstecken muss? Exceptions,

    Wenn Du dich an RAII hältst, dann ist alles automatisch Exception-safe.

    hm schrieb:

    multithreading

    Das kannst Du in Java genauso verkacken wie in C++. In Rust ist das schon viel schwieriger.

    hm schrieb:

    Wie sieht's eigentlich aus mit der Frage ob man etwas auf dem Stack oder dem Heap anlegt? Da ich nie wirklich produktiv C++ programmiert habe, weiß ich gar nicht, wie man das abwägt?

    Du verwendest einfach den kleinstmöglichen Gültigkeitsbereich auf'm Stack, falls möglich. Dank Move Semantics kann man einige Objekte auch effizient von A nach B umziehen lassen (z.B. von einer Fuktion in eine andere, jeweils im Stackframe, also bei der Parameterübergabe oder Rückgabe), ohne dass man da mit Heap-Allozierung und Pointern arbeiten muss. Wenn der Typ T "unhandlich" ist -- sizeof(T) groß oder T ist nicht effizient "move-bar" -- dann kann man eine Indirektion einbauen. Zum Beispiel über std::unique_ptr. Ich komme damit für fast alle Situationen aus. Das mag aber auch an meiner Anwendungsdomäne liegen. Es gibt sicherlich andere Fälle, wo es komplizierter wird.



  • Dann ist das ja alles weniger dramatisch, als gedacht.

    Zusätzlicher Denk-Aufwand kommt dann wahrscheinlich echt erst bei der Frage Heap <> Stack auf, hat aber bestimmt auch seine Vorteile, die Wahl zu haben.

    Du magst wohl Rust? 😃 Könnte man sicherlich auch mal ein Buch zu lesen. Aber dann hat man halt wieder nur ein Buch gelesen und nicht wirklich damit gearbeitet. Hm.



  • Was genau begeistert Euch eigentlich an C++ so sehr,

    Naja persönliche Begeisterung mag das eine sein ...

    Oftmals hat man aber Projektgegebenheiten zu berücksichtigen ...

    - Hat man 3d. Party libs in C/C++ ist der Aufwand eines Wrappers manchmal auch zweilhaft, weil der Rest Zu gring für den Aufwand ist ...
    - Performance auf CPU Seite
    - Du kriegst nen Bulk an C++ Entwicklern, den willst doch wohl ned Java oder C# beibringen auf Projektkosten ...

    Und Qt hat mittlerweile auch von der Entwicklungsgeschwindigkeit echt angezogen so das die unenrschiede nimmer so gross sind. Obwohl Qt wie alle anderen GUI-Libs recht komisches C++ sind ^^

    Ciao ...



  • Vielen Dank für eure Antworten.

    [...] wie [man] die Sprachmittel effektiv einsetzen kann[] [...]

    [...]"Within C++, there is a much smaller and cleaner language struggling to get out."[...]

    Genau darum gehts hier eigentlich in diesem Thread (theoretisch)

    @bad==ugly?:
    Ich glaub du hast nicht verstanden, was meine Intention war: Es geht mir nicht um Pro und Contra Argumente für die Verwendung von C++, genauso wenig wie es mir um Java vs. C++ geht (Ich sagte doch ausrücklich, mich interessiert nicht "Was ist die beste Programmiersprache"), sondern wenn schon feststeht, dass man C++ verwendet, was man gerne und oft verwenden/tun sollte und wovon man lieber die Finger lässt.



  • Deterministische Destruktoren ermöglichen neuen Herangehensweisen. Sowas kennt man in Java nicht, deswegen vermisst man das auch nicht. Aber wenn man sich in C++ daran gewöhnt hat, dann will man das auch nicht mehr vermissen. Ich schreibe ziemlich oft Scope Guard Objekte, die im Destruktor etwas machen. Die leg ich dann einfach auf dem Stack ab und muss mich nicht mehr großartig drum kümmern.


Log in to reply