GC vs RAII



  • dachschaden schrieb:

    Nein, ist keine Verspottung. Aber wer kann schon mit Superskalarität etwas anfangen, außer Compilerbauer und Nerds? 😉

    Alle hier.
    Wer Fragen hat, der fragt.
    Wer anderer Meinung ist, der widerspricht.
    Ich verstehe und liebe C++.de als Fachforum.



  • volkard schrieb:

    RAII kümmert sich um alle Ressourcen. Auch offen Datenbankverbindungen und eben alles, was sofort wegmuss. Ohne daß man sich im Code drum kümmern muss.

    Dafür gibt's in Java seit Version 7 das try-with-resources Statement.

    Manchmal isses gemein lästig, wenn Klassen aus der Standardlib keine tiefen Kopien können.

    Beziehst du das auf Java? Die clone()-Methode macht doch genau das. 😕

    L. G.,
    IBV



  • dachschaden schrieb:

    hustbaer schrieb:

    Und natürlich bedeutet new auch nicht einen Kernel-Call pro new Aufruf.

    Mit solchen Aussagen wäre ich vorsichtig, das hängt, wie du bereits sagtest, von der Laufzeitumgebung ab. Ich erinnere mich (*snip*)

    Ist jetzt Interpretationssache.
    Ich habe natürlich nicht gemeint dass es nicht möglich wäre dass 1x new == 1x Kernel-Call. Ich meinte bloss üblicherweise, und auf allen Plattformen die kein totaler Schrott sind, so ist.



  • IBV schrieb:

    volkard schrieb:

    RAII kümmert sich um alle Ressourcen. Auch offen Datenbankverbindungen und eben alles, was sofort wegmuss. Ohne daß man sich im Code drum kümmern muss.

    Dafür gibt's in Java seit Version 7 das try-with-resources Statement.

    Was auch sehr nötig war. Aber kein Ersatz für RAII wie man es in C++ machen kann ist.

    Konkret fehlt z.B. die Möglichkeit Member-Variablen als "owned resource" zu deklarieren. Die Idee dabei wäre dass einer Klasse die "owned resource" Member hat vom Compiler automatisch ein close() Funktion implementiert wird. Bzw. wenn man die "close" Funktion selbst implementiert (weil man noch andere Dinge machen darin muss), es eine Möglichkeit gibt darin dann eine "default-close" Funktion aufzurufen. Die dann wieder das macht was die compilergenerierte "close" Funktion gemacht hätte. Ich programmiere zwar kein Java, aber genau diese Funktion wünsche ich mir in C# schon öfter mal.

    Und dann wäre da noch die Sache mit den fehlenden Value-Types. Denn RAII heisst für mich genauso dass ich sowas wie shared_ptr implementieren kann, ohne dass der Client-Programmer wissen und dran denken muss wo er überall eine neue Kopie des shared_ptr erzeugen oder eine bestehende entsorgen muss. Und dafür braucht man Value-Types -- mit RAII Support. Auch das fehlt in C# leider *.

    IBV schrieb:

    Manchmal isses gemein lästig, wenn Klassen aus der Standardlib keine tiefen Kopien können.

    Beziehst du das auf Java? Die clone()-Methode macht doch genau das. 😕

    Ne ich denke er meint die Collections, die eben Collections und keine Container sind.

    * Ich weiss schon dass es Value-Types aka "structs" in C# gibt. Und dass auch "structs" IDisposable implementieren können. Und dass der Compiler für lokale Variablen von solchen Typen sogar selbständig den IDisposable.Dispose Aufruf einfügt. Nur wird das alles dadurch kaputt gemacht dass "structs" in C# immer "blittable" sind, d.h. einen compilergenerierten Copy-Ctor und Assignment-Operator haben der einfach nur Byte-für-Byte die Daten rumkopiert.



  • try-with-resources ist für mich überhaupt kein Ersatz für RAII.
    Das gab es im Prinzip schon immer, denn es macht ja nichts anderes als daraus ein try...catch...finally{dispose} zu basteln.
    Es verkürzt einfach nur die Schreibweise.
    Aber ich muss (müsste) weiterhin bei jeder Klasse die ich verwende nachschauen, ob die gerne was disposen möchte.
    In C++ nutze ich einfach die Klasse und wenn die was aufräumen möchte, muss ich davon nichts wissen.



  • dachschaden schrieb:

    - Kann auch langsam sein. Sagen wir, du willst erst mal nur 100.000 Objekte auf dem Heap haben, diese aber nicht unbedingt initialisieren. Mit RAII hast du dann wieder 100.000 Calls des Konstruktors, die gemacht werden müssen.

    Der Unterschied ist, dass man in Java alles auf dem Heap anlegt und in C++ eher nicht.

    Wenn ich 100.000 Objekte in Java benötige, dann muss ich 100.000 mal new aufrufen und dynamischen Speicher anfordern. Das geht in Java sehr schnell.

    Wenn ich 100.000 Objekte in C++ benötige, dann lege ich einen std::vector mit 100.000 Elementen an, welcher alle 100.000 Elemente mit einem new-Aufruf alloziiert. Und das geht mit ziemlicher Sicherheit schneller, als die sehr schnellen 100.000 Aufrufe in Java.

    Ich gehe mal davon aus, dass beide Sprachen der Optimierer keine Probleme hat, den Konstruktoraufruf geeignet zu optimieren. In C++ habe ich möglicherweise einen Standardkonstruktor, welcher Inline ist. Da "sieht" der Compiler, was er machen muss und hat die Möglichkeit zu optimieren. Bei Java sieht er es zur Laufzeit und auch dort werden ähnliche Optimierungen erfolgen.

    In C++ programmiere ich eben anders. Daher ist es nicht sinnvoll, die Allokation von Speicher zu benchmarken, da ich in C++ eben weniger Allokationen machen muss.

    So nebenbei ist in C++ der Code zum anlegen von 100000 Elementen auch wesentlich übersichtlicher:

    std::vector<Point> points(100000);
    
    List<Point> points = new ArrayList<Point>();
    for (int i = 0; i < 100000; ++i)
      points.add(new Point());
    


  • dachschaden schrieb:

    So nebenbei ist in C++ der Code zum anlegen von 100000 Elementen auch wesentlich übersichtlicher:

    std::vector<Point> points(100000);
    
    List<Point> points = new ArrayList<Point>();
    for (int i = 0; i < 100000; ++i)
      points.add(new Point());
    

    Das ist jetzt ein Scherz oder? Soviel Code für so eine simple Sache?

    Mir ist auch eigentlich bei Java egal, ob das theoretisch langsamer oder gleich schnell wie C++ ist. Ich sehe Java-Anwendungen und sehe C++-Anwendungen und da gewinnt bei mir IMMER das C++-Programm in Sachen Performance.

    Habt ihr euch mal den neuen SceneBuilder für JavaFX angesehene? Der hat letzlich beim Ausprobieren, von einer Hand voll Widgets, meinen dicken i7 mit guter Grafikkarte locker in die Knie gezwungen. Da ist Battlefield4 genügsamer.


  • Mod

    Wann habt Ihr das letzte mal eine Liste mit 100.000 "Standardpunkten" benoetigt?

    Zeigt doch mal den Unterschied, wenn Ihr 100.000 Punkte erstellt, die alle auf einer Funktion liegen. Also zum Beispiel, wenn Ihr etwas plotten moechtet. Besser noch: Baut mal eine Methode, aus der Ihr so eine Liste an Punkten rauskriegt und zeigt diese inklusive dem Methodenaufruf.



  • tntnet! Du unterschlägst aber, das die C++ Variante nicht der Java-Variante entspricht!
    In deinem C++ Beispiel kann man nur Objekte genau eines Typs anlegen: Point! Und zwar ausschließlich Points, keine Objekte die von Point erben.

    Jetzt kann man natürlich sagen, ich brauche nur den einen Typ. Aber dann sage das auch. So ist der Vergleich leider für den Popo! Weil sobald du Point als Basis-Typ haben willst, ist der C++ Vorteil wieder dahin!



  • Artchi schrieb:

    Weil sobald du Point als Basis-Typ haben willst, ist der C++ Vorteil wieder dahin!

    std::vector<std::shared_ptr<Point>> points(size, std::make_shared<Point>());
    

    Macht in etwa dasselbe wie der Javacode und ist zeilenmäßig trotzdem besser.



  • Na also, wenn dann bitte gleich richtig. Geht doch! Aber das von Tntnet war ne Frechheit!

    Um die Codekürze ging es mir nicht vorrangig. Das ist nur nice-to-have. Es geht darum, was es macht und dann müssen beide Beispiel gleiches können.


  • Mod

    Nathan schrieb:

    std::vector<std::shared_ptr<Point>> points(size, std::make_shared<Point>());
    

    Macht in etwa dasselbe wie der Javacode und ist zeilenmäßig trotzdem besser.

    Ist immer noch irrelevant. Niemand braucht 100.000 Punkt Objekte, die alle mit dem Standardkonstruktor erstellt wurden und somit alle gleich sind.

    Wenn Ihr zu einem realistischeren Szenario geht, dann wird die Codelänge nicht mehr wesentlich von einander abweichen.



  • Gregor! Ja, das stimmt. Ich verstehe das Ziel dieses künstlichen Konstrukts auch nicht. In der Praxis sieht Code anders aus. Selbst für einen Unittest wäre das Beispiel unrealistisch.



  • Gregor schrieb:

    Nathan schrieb:

    std::vector<std::shared_ptr<Point>> points(size, std::make_shared<Point>());
    

    Macht in etwa dasselbe wie der Javacode und ist zeilenmäßig trotzdem besser.

    Ist immer noch irrelevant. Niemand braucht 100.000 Punkt Objekte, die alle mit dem Standardkonstruktor erstellt wurden und somit alle gleich sind.

    Insbesondere macht das nicht 100k Point Objekte, sondern einen Vektor aus 100k shared_ptr die alle auf das selbe Point Objekt verweisen... 😉


Anmelden zum Antworten