welche vorteile bietet c++ gegenüber c



  • Ich habe jetzt nicht alle Beiträge hier gelesen, aber es scheint ja irgendwie um Exceptions zu gehen oder so. Da geb ich mal meinen Mist dazu 😉

    Ich habe vor kurzem mal ein etwas aufwendigeres Programm geschrieben, erst in C und dann das Ganze noch mal in C++. Und ich muss doch gestehen, dass C++ mit exceptions hier ganz erhebliche Vorteile bietet. Das "sich durch den Stack werfen" und dass alle STL-Container problemlos aufgelöst werden ist einfach genial. Die C-Fehlerbehandlung konnte nahezu vollständig über Bord geworfen werden, viele Dinge wurden vereinfacht, der Code war in C++ einfach mal halb so groß!
    Und langsamer läuft das mit C++ auch nicht.



  • Irgendwer schrieb:

    In "More effective C++", Kapitel 3.3, Seite 73ff gibt es ein Beispiel mit Session-Objekten.

    Habe das Buch leider gerade nicht greifbar..
    Aber Scott Meyers sagt doch normalerweise etwas zu den Problemen und wie man damit umgehen kann.

    Das tut er. Und sein Rat ist: Kritische Funktionen zur Ressourcenfreigabe in eine extra Funktion auslagern, diese im Dtor aufrufen und ein try-catch um diesen Funktionsaufruf herum, der die Exception verschluckt.

    Dass C++ Destruktoren nicht viel taugen, wenn es um die saubere Zerstörung von Objekten und die Freigabe von Ressourcen geht.

    Diese Ansicht finde ich etwas übertrieben. Wie gesagt, ich kenne das Beispiel von Scott Meyers jetzt nicht aus dem Gedächtnis, aber wann spielt das im Alltag eine Rolle?

    Na ja, immer wenn man im Destruktor was freigibt, was throwen kann. Ob die Auswirkungen immer extrem sind? Nein. Aber ist es trotzdem sehr ungeschickt? Ich finde ja.

    Selbst fstream ist davon betroffen, denn der Dtor führt ein close() aus. Grad mal aus /usr/include/c++/4.4.5/fstream rausgezogen:

    //Gehört zur Klasse basic_filebuf
    
    /**
     *  @brief  The destructor closes the file first.
     */
    virtual
    ~basic_filebuf()
    { this->close(); }
    

    Und was wäre ein besserer Mechanismus als RAII (sprich Ressourcenfreigabe in Destruktoren)? Etwa eine Cleanup() Methode für jede Klasse? Wenn's sein muss kann man ja beides bereitstellen und dafür sorgen, dass der Destruktor nur im Notfall tatsächlich etwas freigeben muss.

    Klar, aber wenn man zu letzterer Methode greift, ist der Destruktor effektiv nutzlos.

    cooky451 schrieb:

    Die C-Fehlerbehandlung konnte nahezu vollständig über Bord geworfen werden, viele Dinge wurden vereinfacht, der Code war in C++ einfach mal halb so groß!

    Das ist nicht verwunderlich, schließlich fällt die angemessene Fehlerbehandlung oft zugunsten einer "Ach, das try-catch relativ weit oben in der Aufrufhierarchie wird schon alles fangen" raus 🙂 C ist keine Sprache, in der man übermäßig produktiv ist. Besonders nicht, wenn man Stringverarbeitung macht oder wert auf gute Fehlerbehandlung legt.



  • GPC schrieb:

    Selbst fstream ist davon betroffen, denn der Dtor führt ein close() aus.

    Und wo ist das Problem?

    Wie genau wuerdest du auf ein fehlschlagendes close reagieren?

    Es gibt genau 2 Gruende warum das fehlschlagen kann:

    1. der file descriptor ist invalid. dh deine invarianten sind verletzt. dh alles ist in einem inkonsistent zustand. sofort shutdown der anwendung (oder zumindest des aktuellen prozesses).

    2. die datei laesst sich trotz gueltigen handles nicht schliessen. entweder ist das filesystem defekt oder das betriebssystem im eimer. beides bedeutet: sofort shutdown des systems.

    Gerade bei Dateien ist das absolut kein Problem. Nahezu alle Faelle wo der Dtor fehlschlagen kann sind sowas. Es gibt sehr sehr sehr sehr wenige Situationen wo ein normale Dtor nicht reicht. Und dann kapselt man das Objekt und zerstoert es manuell und reagiert auf die Fehler.



  • Shade Of Mine schrieb:

    GPC schrieb:

    Selbst fstream ist davon betroffen, denn der Dtor führt ein close() aus.

    Und wo ist das Problem?

    Das habe ich, denke ich, schon ausreichend ausgeführt 🙂 Es ging mir auch nicht um fstream im Speziellen, ich wollte nur ein Beispiel geben 🙂

    Wie genau wuerdest du auf ein fehlschlagendes close reagieren?

    Situationsabhängig. War die Datei nicht übermäßig wichtig, kann ich den Prozess auch weiterlaufen lassen, würde aber trotzdem gerne iwie mitbekommen, dass da was im Busch ist. Es kann auch sein, dass die Datei nicht mehr verfügbar ist, weil das Netzwerklaufwerk getrennt wurde. Dann ist weder das OS noch das FS im Eimer.

    Edit: Mir ist natürlich klar, dass man auch die angesprochenen Fälle behandeln kann 😉 Ich kann es nur nicht mehr hören, wenn so getan wird, als wäre RAII und Resourcenrelease im Dtor der Weg zum perfekten Glück.



  • freigeist3 schrieb:

    ...Normalerweise unterhalte ich mich ja auch mit meinen Berkeley Freunden über's
    Programmieren...
    ...Dämliches Amateur-Niveau hier ... und sofort wird man angeflammt ...

    Was erwartest Du denn? Wenn ihr Euch hier gegenseitig Kompetenzen absprecht und jeder mit irgendwelchen provokanten bzw eventuell leicht übertriebenen Behauptungen daherkommt, ist das doch zu erwarten. Du kommst ja auch gleich mit einem hohen Ross daher geritten. "Ich hab schon ein tolles Schachprogramm in C geschrieben, was besser als das C++ Prog von meinem Kumpel war" - "Ich unterhalte mich sonst mit meinen Berkely Freunden" - etc. Du willst wahrscheinlich auch noch, dass man Dich für Deine Leistungen und Bekanntschaften beglückwünscht, wie?
    Das strotzt ja nur so vor Arroganz. Was erwartest Du denn wirklich? Sei mal ehrlich. Du hattest nur grad mal Langeweile und wolltest Dich ein bissel beschäftigen...

    Mindestens 10 Seiten Zeitverschwendung in diesem Thread.



  • GPC schrieb:

    Ich kann es nur nicht mehr hören, wenn so getan wird, als wäre RAII und Resourcenrelease im Dtor der Weg zum perfekten Glück.

    Ich kenne nichts was auch nur annaehernd so gut ist. Perfekt ist was anderes - keine Frage. Aber bei weitem das beste was es gibt.



  • Shade Of Mine schrieb:

    Ich kenne nichts was auch nur annaehernd so gut ist. Perfekt ist was anderes - keine Frage. Aber bei weitem das beste was es gibt.

    +1



  • dot schrieb:

    Shade Of Mine schrieb:

    Ich kenne nichts was auch nur annaehernd so gut ist. Perfekt ist was anderes - keine Frage. Aber bei weitem das beste was es gibt.

    +1

    +1



  • Das tut er. Und sein Rat ist: Kritische Funktionen zur Ressourcenfreigabe in eine extra Funktion auslagern, diese im Dtor aufrufen und ein try-catch um diesen Funktionsaufruf herum, der die Exception verschluckt.

    Na, damit ist doch auch niemandem geholfen. Das Problem ist immer noch exakt das selbe, man hat es nur in eine weitere Funktion ausgelagert.

    volkard schrieb:

    dot schrieb:

    Shade Of Mine schrieb:

    Ich kenne nichts was auch nur annaehernd so gut ist. Perfekt ist was anderes - keine Frage. Aber bei weitem das beste was es gibt.

    +1

    +1

    +1



  • Irgendwer schrieb:

    Das tut er. Und sein Rat ist: Kritische Funktionen zur Ressourcenfreigabe in eine extra Funktion auslagern, diese im Dtor aufrufen und ein try-catch um diesen Funktionsaufruf herum, der die Exception verschluckt.

    Na, damit ist doch auch niemandem geholfen. Das Problem ist immer noch exakt das selbe, man hat es nur in eine weitere Funktion ausgelagert.

    Genau so ist es.
    Aber mit der ausgelagerten Funktion kann man doch gelegentlich arbeiten, um dem Benutzer einen hilfreichen Hinweis zu geben, sogar ihm eine zweite Chance zu geben.
    Er kann zum Beispiel den "Speichern"-Knopf drücken, worauf flushAndClose() nicht funktioniert und eine Exception wirft, und er bekommt die Meldung und darf es (nach Einbau einer neuen Festplatte, hahah, nee, nach Einstecken eines besseren USB-Sticks) nochmal versuchen.
    Naja, eigentlich ist close() außen vor und es geht nur um flush().

    Es ändert nichts daran, daß die Anwendung nicht gescheit reagieren kann, wenn was kritisches nicht klappt. Vermutlich hat man in jeder Programmiersprache das selbe Problem, nur hat man in vielen anderen Sprachen so heftige Zusatzprobleme, daß man sich gar nicht auf das Hauptproblem besinnen kann. In Java zum Beispiel ist zeitnahes Aufräumen nicht sinnvoll denkbar, zeitlich geordnetes Aufräumen gar nicht eingebaut, Überhaupt-Aufräumen nicht definiert, und es klappt trotzdem! Dafür gibt es doch Backups, Logfiles und atomische Transaktionen. C++ macht es sau-angenehm und für meine Begriffe sogar sau-einfach. Und wirksam.
    Will man in Java-Spachen überleben, muß man lustige Saqchen wie http://www.devx.com/dotnet/Article/33167
    machen. Alles nur, weil eine künstliche Trennung zwischen Speicher-Ressource und Andere-Ressource gemacht wurde, ganz ohne Not. Das ist kompliziert, langsam und unsicher. Wozu? Historisch läßt es sich leicht erklären, wenn man sich an Oak erinnert.



  • freigeist3 schrieb:

    Fang mal mit nem simplen Spielbäumchen an und wenn sich Dein vertrolltes Hirn sowas bis in 5 Jahren zusammengedacht hat (Es gibt fast keinen Algo, den man dazu nicht benötigt!!), kannst ja nochmal Leuten die Kompetenz
    absprechen versuchen, die Du nicht kennst.

    Als ob sich jeder seine Zeit mit so simplen Dingen wie gelösten Problemen verschwenden muss. Bevor du andere zurechtweißt, soltlest du dein Können mal an richtigen Problemen zeigen. Wie wärs zum Beispiel mit reellwertigen Zustandsräumen und reellwertigen Funktionen? Oder Problemen die die Markov-Eigenschaft verletzen? Alles andere ist doch nur Kinderkram und eine Beleidigung der Intelligenz der Forennutzer hier.



  • Shade Of Mine schrieb:

    GPC schrieb:

    Ich kann es nur nicht mehr hören, wenn so getan wird, als wäre RAII und Resourcenrelease im Dtor der Weg zum perfekten Glück.

    Ich kenne nichts was auch nur annaehernd so gut ist. Perfekt ist was anderes - keine Frage. Aber bei weitem das beste was es gibt.

    Wenn du geschrieben hättest "Ich kenne nichts [in C++] was auch nur annaehernd so gut ist", dann würde ich zustimmen.. ich bin nur vom Gesamtkonzept an der Stelle nicht übermäßig begeistert.

    volkard schrieb:

    Irgendwer schrieb:

    Das tut er. Und sein Rat ist: Kritische Funktionen zur Ressourcenfreigabe in eine extra Funktion auslagern, diese im Dtor aufrufen und ein try-catch um diesen Funktionsaufruf herum, der die Exception verschluckt.

    Na, damit ist doch auch niemandem geholfen. Das Problem ist immer noch exakt das selbe, man hat es nur in eine weitere Funktion ausgelagert.

    Genau so ist es.
    Aber mit der ausgelagerten Funktion kann man doch gelegentlich arbeiten, um dem Benutzer einen hilfreichen Hinweis zu geben, sogar ihm eine zweite Chance zu geben.

    Erst kürzlich hast du noch gesagt, die "ReleaseResources"-Funktion heilt nichts 🙂



  • Wenn du geschrieben hättest "Ich kenne nichts [in C++] was auch nur annaehernd so gut ist", dann würde ich zustimmen.. ich bin nur vom Gesamtkonzept an der Stelle nicht übermäßig begeistert.

    Wie würdest du es denn gerne gelöst wissen? Oder in welcher Sprache hat man bessere Werkzeuge, die solche (seltenen) Probleme lösen (Garbage Collection hat natürlich die gleichen Probleme, nur das sie nicht auftreten, wenn es der Programmierer will, sondern wenn der GC meint das Objekt zerstören zu können).



  • GPC schrieb:

    Wenn du geschrieben hättest "Ich kenne nichts [in C++] was auch nur annaehernd so gut ist", dann würde ich zustimmen.. ich bin nur vom Gesamtkonzept an der Stelle nicht übermäßig begeistert.

    Ich kenne keine Sprache wo ich mich nicht immer mal wieder nach RAII sehne.

    Kein Konzept dass ich kenne kommt an RAII ran. Welche Sprache bzw. welche Konzepte würdest du besser finden?



  • Irgendwer schrieb:

    Wie würdest du es denn gerne gelöst wissen? Oder in welcher Sprache hat man bessere Werkzeuge, die solche (seltenen) Probleme lösen (Garbage Collection hat natürlich die gleichen Probleme, nur das sie nicht auftreten, wenn es der Programmierer will, sondern wenn der GC meint das Objekt zerstören zu können).

    Ja, würd mich auch interessieren in welcher Sprache du das besser gelöst siehst.
    Garbage Collection ist jedenfalls keine Lösung, im Gegenteil. Zwar brauchst du dich dort um Speicher nichtmehr zu kümmern aber alles andere wird ungemein umständlicher. Darum braucht man dann in C# und Java so Zeug wie finally Blöcke und den Dispose Pattern. Beides ist, wenn du mich fragst, RAII weit unterlegen. Ich mag C#, aber trotzdem wünsch ich mir dort sehr oft ich könnte RAII verwenden...



  • Ein GC hat ja auch das Problem. Nehmen wir an, aus irgendeinem Grund könnte das Freigeben von Speicher fehlschlagen. Banalere Variante: der Finalizer eines Objekts wirft eine Exception.
    Zumindest beim Java-GC wird diese einfach ignoriert...



  • Um die letzten vier Posts also zusammenzufassen:
    - RAII ist nicht perfekt, aber am Besten. Was schlägst Du Besseres vor?
    - Um Dir das Argument vorwegzunehmen: GC bringt auch nix.



  • dot schrieb:

    Ich mag C#, aber trotzdem wünsch ich mir dort sehr oft ich könnte RAII verwenden...

    Du hast in C# using() Blöcke. Die helfen oft. Python bietet das auch an (with). Ist ganz OK, halt eine light Variante von RAII.



  • Shade Of Mine schrieb:

    Du hast in C# using() Blöcke. Die helfen oft. Python bietet das auch an (with). Ist ganz OK, halt eine light Variante von RAII.

    using Blöcke zählen für mich zum Dispose Pattern. Und ja, ist in einigen Fällen ganz brauchbar, aber eben bei weitem nicht so mächtig wie RAII...



  • Shade Of Mine schrieb:

    Kein Konzept dass ich kenne kommt an RAII ran. Welche Sprache bzw. welche Konzepte würdest du besser finden?

    Leider ist das Problem in keiner mir bekannten Sprache richtig gut gelöst 😕 Ich habe ja auch keine Sprache als Referenz bzw. Vergleich genannt, sondern mich auf die Problematik des Konzepts beschränkt (von der auch andere Sprachen betroffen sind).
    Ich fand aber das Konzept der Conditions in Lisp sehr interessant, habe aber zu wenig Ahnung von Lisp im Detail, um hier die Nachteile im Gesamtzusammenhang der Sprachfeatures aufzudecken.

    dot schrieb:

    Shade Of Mine schrieb:

    Du hast in C# using() Blöcke. Die helfen oft. Python bietet das auch an (with). Ist ganz OK, halt eine light Variante von RAII.

    using Blöcke zählen für mich zum Dispose Pattern. Und ja, ist in einigen Fällen ganz brauchbar, aber eben bei weitem nicht so mächtig wie RAII...

    Das using-Statement ist RAII in .NET, da using genauso wie RAII auf dem Prinzip von "scoped usage" basiert. Der Unterschied ist, dass es sich auf unmanaged resources wie Datenbankhandles, Session IDs, Dongleverbindungen etc. beschränkt, denn managed resources verwaltet ja die CLR. Allerdings ist das Dispose-Pattern nicht besonders intuitiv. Der einzige Vorteil gegenüber RAII in C++ ist, dass man die Exceptions, die ein vom Finalizer aufgerufenes Dispose wirft, über den Finalizer der Klasse weiter nach oben geben kann, was ja in C++ nicht möglich ist. Ansonsten ist C++ RAII an der Stelle aber einfacher, weil man nicht extra an das using-Statement denken muss.


Anmelden zum Antworten