Fehlerbehandlung in einer Engine



  • knivil schrieb:

    Ich habe gesehen, dass spaeter Design by Contract angerissen wird, aber was hat das mit Exceptions zu tun? (Ok, bei konsequenter Umsetzung braucht man ein assert nur fuers Debugging. But what's the point?)

    Lies die Artikel einfach einmal durch und poste nicht dauernd dazwischen.

    Danach können wir uns unterhalten.



  • Also ich hab mir jetzt die letzten 3 Seiten Streitgespräch durchgelesen und ich muß sagen das meine Sympatie für Exceptions nachwievor nicht gestiegen sind. Ich stimme Knivil eigentlich fast komplett zu, ein Rückgabewert kann abgefangen werden, muß aber nicht, wenn sich der Nutzer Sicher ist das seine angaben korrekt sind kann er ihn Ignorieren, so wie es einige Leute ja bei DX auch tun zB. Mit Exceptions wäre man verpflichtet überall wo in der Engine Exceptions geworfen werden nen Tryblock drum zu bauen nur um das Teil zu fangen ohne einen totalen Programmabsturz zu bekommen, das spricht in meinen augen nicht gerade für Exceptions. Und was die Rückgabewerte angeht, ein halbes Dutzend Fehlercodes dürfte eigentlich schon ausreichen um zu zeigenw as schief gelaufen ist und für Details gäbe es ja noch das Logbuch.



  • knivil schrieb:

    Ich verstehe it0101@loggedoff recht gut, siehe erster empfohlener Artikel von Davere.

    Gute Exceptionsichere Programme in C++ enthalten so gut wie kein try/catch. Das ist einer der Punkte aus meinen 2 Artikeln. Wenn du natürlich immer nur den Artikel hernimmst der die Grundlagen von Exceptions erklären soll - klar dass der nicht immer perfekt ist.

    Aber wenn du meine Artikel gelesen hast, wirst du lernen dass es unterschiedliche Fehler gibt und auf die müssen wir unterschiedlich reagieren (assert kann nicht auf alle Fehler reagieren). Und Vertragsverletzungen kann es durchaus auch in einem korrekten Programm geben.

    Und warum man try/catch nur an ein paar zentralen stellen verwendet und RAII die arbeit machen lässt - das erfährst du auch noch.

    lohnt sich also



  • Xebov schrieb:

    Ich stimme Knivil eigentlich fast komplett zu, ein Rückgabewert kann abgefangen werden, muß aber nicht, wenn sich der Nutzer Sicher ist das seine angaben korrekt sind kann er ihn Ignorieren, so wie es einige Leute ja bei DX auch tun zB.

    Deshalb gelten Spiele generell auch als so Stabil, nicht wahr?

    Fehler darf man nie ignorieren und das ist der Punkt. Natürlich ist es einfach sie zu ignorieren, aber das beste kommt jetzt erst:
    exception erlauben es dir sie zu ignorieren und nur an einer zentralen stelle dich mit ihnen zu befassen.

    Mit Exceptions wäre man verpflichtet überall wo in der Engine Exceptions geworfen werden nen Tryblock drum zu bauen nur um das Teil zu fangen ohne einen totalen Programmabsturz zu bekommen, das spricht in meinen augen nicht gerade für Exceptions.

    Du hast einfach nur nicht meine Artikel gelesen.

    try/catch hast du so gut wie nie. Meistens habe ich ein try/catch in main() und dann vielleicht auf 5000 LOC ein try/catch - wenn überhaupt.



  • knivil schrieb:

    // in is a valid input stream
    // out is a valid output stream
    // passwd is a non empty string
    encode( Stream in, Stream out, String passwd );
    

    Wie der Benutzer zu den gueltigen Streams kommt ist jetzt seine Sache.

    Gerade Streams sind ein schlechtes Beispiel. Je nach Stream kann der Benutzer nicht gewährleisten, dass er valide ist. Es kann der Speicher ausgehen, das hinterliegende File wegsterben, ein Socket abrauchen, weil der Stecker auf der Gegenseite gezogen wurde, ein DBMS abgekackt ist, etc.
    Das sind alles Ausnahmen (man sagt, "Exception" würde auf deutsch Ausnahme heissen 🤡 ) zum regulären Betrieb.
    Da ist es nichtmal wichtig, was Du mit dem wagen Begriff "Benutzer" meinst. Ist es der Anwender, so sollte er nichtmal davon wissen, dass irgendwo sowas wie Streams werkeln. Ist es der Anwender einer Streamklasse, so kann er nichts gegen die äußeren Einflüsse tun.
    Gerade solche unerwarteten äußeren Einflüsse lassen sich besonders gut durch Ausnahmen abfangen. in vielen der oben genannten Fälle ist ein Vertrag nicht gesichert einzuhalten. Dabei ist es vor allem wichtig, dass Programm in einem validen (damit ist nicht lauffähig gemeint) Zustand zu halten. Ist dies nicht möglich, muss das Programm beendet werden.



  • Ich habe irgendwie das Gefühl, dass wir eigentlich von den Ansichten garnicht sooo weit auseinander liegen. Allerdings scheint jede Seite zu verbohrt zu sein, sich mal mit den Argumenten der anderen Seite zu beschäftigen. ( siehe letzter Beitrag von Tachyon. In Wirklichkeit interessiert es ihn einen feuchten Dreck, was ich wirklich sagen wollte. Zumindest drängt sich die Vermutung auf. )

    Shade of Mine lässt absolut nix auf seine Artikel kommen. Er hat eben seine Meinung und alles andere ist seiner Meinung nach falsch.

    Knivil und ich sind von massivem Exception-Einsatz nicht überzeugt.

    Kompromisse oder ähnliches scheint es nich zu geben - damit ist das Thema eigentlich erledigt. ( Dennoch werde ich mir die Artikel noch komplett durchlesen 😉 Wenn da gut argumentiert wird, bin ich gern bereit mich überzeugen zu lassen ). Die Diskussion hier führt allerdings zu NULL ( oder 0 ).



  • Knivil und ich sind von massivem Exception-Einsatz nicht überzeugt.

    Shade of Mind auch nicht. Ich finde es aber gut, dass die Diskussion von der reinen Polemik zurueck zu Argumenten gefunden hat. Und NULL ( oder 0 ) ist immer noch besser als gar nix. 🙂



  • it0101@loggedoff schrieb:

    ...siehe letzter Beitrag von Tachyon.

    Doch. Du scheinst zu denken, der Sinn von Exceptions liegt darin, ein Programm durch den massiven Einsatz von try-catch-Blöcken irgendwie lauffähig zu halten. Zumindest lässt einen Deine Interpretation des von Dir zitierten Artikelschnippsels das vermuten.
    Das ist aber nicht der Sinn. Der Sinn ist es, das Programm in einem validen Zustand zu halten. Ist eine Exception im Konext eines Programms so schwerwiegend, dass es nicht mehr valide laufen kann, so muss die Exception zum Abbruch des Programms führen. In dem Fall lässt man sie bis zur obersten Instanz durchfallen. Im Falle von C++ als entweder in etwas wie catch(...){cerr << "Serious error occurred, terminating...\";} an höchster Stelle, oder gleich ans OS.



  • Ist eine Exception im Konext eines Programms so schwerwiegend, dass es nicht mehr valide laufen kann, so muss die Exception zum Abbruch des Programms führen.

    Da geh ich absolut mit.

    Begründet aber immer noch nicht, warum man Exceptions an jeder Ecke benutzen muss und Rückgabewerte in Form von Errorcodes generell scheisse sein sollen.



  • Shade Of Mine schrieb:

    Ich stimme Knivil eigentlich fast komplett zu, ein Rückgabewert kann abgefangen werden, muß aber nicht, wenn sich der Nutzer Sicher ist das seine angaben korrekt sind kann er ihn Ignorieren, so wie es einige Leute ja bei DX auch tun zB.
    Deshalb gelten Spiele generell auch als so Stabil, nicht wahr?

    Fehler darf man nie ignorieren und das ist der Punkt. Natürlich ist es einfach sie zu ignorieren, aber das beste kommt jetzt erst:
    exception erlauben es dir sie zu ignorieren und nur an einer zentralen stelle dich mit ihnen zu befassen.

    Naja wer sagt dennd as man sie Ignoriert? ob ich einen Rückgabewert habe und denn gegenteste oder ob ich die Exception verarbeite läuft aufs gleiche hinaus, Fehlerbehandlung. Und die Zentrale Stelel ist nicht imemr das richtige, ich habe zB nur 3 Probleme die Auftreten können, NULL-Zeiger, fehlende Dateien oder das irgendeine der vielen DX Funktionen mal streikt, das gibt nen Eintrag ins Log mit genauen infos und dann halt ne Fehlerrückgabe und auf die muß man sofort Reagieren, wenn du 10 Models lädst und eins davon is nicht da dann musste ja direkt handeln da kannste ja nicht warten bis alles fertiggerendert ist und dir die Zugriffsverletzungen um die Ohren fliegen. Mir fällt auch ehrlich gesagt kein Fehler ein bei dem man hätte Zentral reagieren können, dazu fehlt mir evtl die Erfahrung was so alles Fehelr evrursachen kann.

    Shade Of Mine schrieb:

    Du hast einfach nur nicht meine Artikel gelesen.

    try/catch hast du so gut wie nie. Meistens habe ich ein try/catch in main() und dann vielleicht auf 5000 LOC ein try/catch - wenn überhaupt.

    Doch ich habe deine Artikel gelesen, den 1. und 2. komplett den Hinetr den Kulissen hab ich angefangen, allein die vielen Blöcke haben mich dann entgültig abgeschreckt weil ich mir dann dachte das kanns ja nicht sein, nen ganzen haufen Blöcke nur für die paar Zeilen Code das schreckt mich ab, warum ist ganz einfach, ich kann jede Menge Blöcke bauen oder eben einfach sagen ERR_FILE_NOT_FOUND, wovon letztere Variante genauso aussagekräftig ist wie die Exceptions, und sie ist direkt zu sehen, man muß sich da nicht durchkämpfen.



  • it0101@loggedoff schrieb:

    Ist eine Exception im Konext eines Programms so schwerwiegend, dass es nicht mehr valide laufen kann, so muss die Exception zum Abbruch des Programms führen.

    Da geh ich absolut mit.

    Begründet aber immer noch nicht, warum man Exceptions an jeder Ecke benutzen muss und Rückgabewerte in Form von Errorcodes generell scheisse sein sollen.

    Das Auswerten von Rückgabewerten kann man einfach vergessen. Exceptions muss man bewusst verwerfen, sonst merkt sie spätenstens das OS.
    Deine Aussage:

    it0101@loggedoff schrieb:

    Wo geworfen wird, muss auch abgefangen werden 😉
    Ohne das Werfen von Exceptions spart man auch die try-catch-Geschichte.

    Meine Aussage:
    Wo geworfen wird, kann man auch abfangen und behandeln. Fängt man die Exception nicht ab, ist sie nicht behandelbar und das Programm bricht ab. Man kann sie die "try-catch-Geschichte" sparen.

    PS: Führt man eine Operation durch, die bei einem Fehler gesichert nicht zu einem fehlerhaften Programmzustand führt, so halte ich entsprechende Rückgabewerte für okay. Ansonsten sollte man doch lieber Exceptions werfen.



  • it0101@loggedoff schrieb:

    Ist eine Exception im Konext eines Programms so schwerwiegend, dass es nicht mehr valide laufen kann, so muss die Exception zum Abbruch des Programms führen.

    Da geh ich absolut mit.

    Begründet aber immer noch nicht, warum man Exceptions an jeder Ecke benutzen muss und Rückgabewerte in Form von Errorcodes generell scheisse sein sollen.

    Das seh ich genauso (BEIDE PUNKTE). Werde mir die Artikel aber auch nochmal genauer zu gemüte führen...
    rya.



  • PS: Führt man eine Operation durch, die die bei einem Fehler gesichert nicht zu einem fehlerhaften Programmzustand führt, so halte ich entsprechende Rückgabewerte für okay. Ansonsten sollte man doch lieber Exceptions werfen.

    Mehr wollte ich eigentlich auch nicht vermitteln.

    Ich wehre mich hier nur gegen das verallgemeinernde Verdammen von ErrorCode-Rückgaben. Das ist nämlich Quatsch.

    Wenn allerdings das Programm aufgrund von Fehlern unter keinen Bedingungen weiterlaufen kann, dann muss eine Exception geworfen werden.

    @Tachyon
    wie ich bereits vorhin sagte: Eigentlich liegen wir garnicht so weit auseinander.

    (von Shade mal abgesehen 😃 )



  • Xebov schrieb:

    Shade Of Mine schrieb:

    Ich stimme Knivil eigentlich fast komplett zu, ein Rückgabewert kann abgefangen werden, muß aber nicht, wenn sich der Nutzer Sicher ist das seine angaben korrekt sind kann er ihn Ignorieren, so wie es einige Leute ja bei DX auch tun zB.
    Deshalb gelten Spiele generell auch als so Stabil, nicht wahr?

    Fehler darf man nie ignorieren und das ist der Punkt. Natürlich ist es einfach sie zu ignorieren, aber das beste kommt jetzt erst:
    exception erlauben es dir sie zu ignorieren und nur an einer zentralen stelle dich mit ihnen zu befassen.

    Naja wer sagt dennd as man sie Ignoriert? ob ich einen Rückgabewert habe und denn gegenteste oder ob ich die Exception verarbeite läuft aufs gleiche hinaus, Fehlerbehandlung. Und die Zentrale Stelel ist nicht imemr das richtige, ich habe zB nur 3 Probleme die Auftreten können, NULL-Zeiger, fehlende Dateien oder das irgendeine der vielen DX Funktionen mal streikt, das gibt nen Eintrag ins Log mit genauen infos und dann halt ne Fehlerrückgabe und auf die muß man sofort Reagieren, wenn du 10 Models lädst und eins davon is nicht da dann musste ja direkt handeln da kannste ja nicht warten bis alles fertiggerendert ist und dir die Zugriffsverletzungen um die Ohren fliegen. Mir fällt auch ehrlich gesagt kein Fehler ein bei dem man hätte Zentral reagieren können, dazu fehlt mir evtl die Erfahrung was so alles Fehelr evrursachen kann.

    Ja, dir fehlt es an Erfahrung. In einem real-world Programm und eine Bibliothek ist immer eine solche, bestehen deine Methoden zu einem großen Teil aus Code der Daten validiert und Fehler entsprechend behandelt. Man könnte sich viel Arbeit sparen, wenn die vielen großen Bibliotheken mit denen man alltäglich zu tun hat selbst Exceptions benutzen würden, nur ist das leider oft nicht der Fall, da diese Bibliotheken nicht C++-spezifisch sind, oder schon sehr alt sind und man früher aus anderen Gründen auf Exceptions verzichten musste.

    DirectX Fehler lassen sich grob in zwei Kategorien einteilen: Programmierfehler (leicht zu beheben nach einem Blick auf die Fehler-Beschreibung von DirectX bzw. kurzem Googeln) und "device-lost". Letzteres kann so gut wie immer passieren, deshalb muss man auch von jedem DirectX Aufruf den Rückgabewert überprüfen.

    DirectX ist überhaupt ein sehr schlechtes Beispiel, da Code der mit DirectX arbeitet nie schön ist, sondern völlig zugekleistert von Fehlerbehandlungscode wird. Ein dünner Wrapper und der Einsatz von Exceptions kann hier wahre Wunder wirken, probier es doch einmal aus 🙂
    Danach kann dein Code so aussehen wie in den ganzen schlechten Spieleprogrammierbücher/-tutorials nur mit dem Unterschied, dass sämtliche Fehler sauber behandelt werden 🙂



  • it0101@loggedoff schrieb:

    [...]

    (von Shade mal abgesehen 😃 )

    Mit dem Unterschied, dass ich (und viele andere) sofort bestätigen würden, dass Shade verdammt viel Ahnung vom Programmieren hat.

    Hört einfach mal auf ihn, im schlimmsten Fall lernt ihr was dazu 👍

    Wenn man sauber mit Errorcodes arbeiten will muss man zwangsweise mit goto arbeiten und man fängt an einen schlechten Exceptionmechanismus nachzubauen, wo ist also der Vorteil von Errorcodes, wenn man Exceptions bereits in der Sprache zur Verfügung hat? Und ich rede hier von Errorcodes, nicht von einem Bool, oder auch mal einem TriBool, für spezielle Funktionen.



  • it0101@loggedoff schrieb:

    [Wenn allerdings das Programm aufgrund von Fehlern unter keinen Bedingungen weiterlaufen kann, dann muss eine Exception geworfen werden.

    Der springende Punkt ist eigentlich, dass auch dann, wenn es unter manchen Bedingungen weiterlaufen kann eine Exception geworfen werden muss. Es gibt ja noch mindestens einen Fall, wo es nicht weiterlaufen kann.



  • Hört einfach mal auf ihn, im schlimmsten Fall lernt ihr was dazu 👍

    Ich weiß selber, dass er ne Menge Plan hat.
    Aber er hat eben auch eine Meinung. Und nur weil er vielleicht in nicht so schlimmen Fällen ( wo das Programm eben weiterlaufen kann ) Exceptions verwendet wo andere eben ErrorCode nutzen, dann heißt das noch nicht, dass seine Lösung die einzig wahre ist.

    Aber das ist eben genau wie mit der uneingeschränkten Nutzung der STL, die hier gern vertreten wird - es gibt immer mehrere Ansichten und es muss nicht immer sein, dass eine der beiden Ansichten komplett und in allen Fällen falsch ist.

    Aber einfach zu sagen: ihr habt keine Ahnung, und ich hab Recht ist nicht die feine Art zu diskutieren.



  • Wenn man sauber mit Errorcodes arbeiten will muss man zwangsweise mit goto arbeiten und man fängt an einen schlechten Exceptionmechanismus nachzubauen, wo ist also der Vorteil von Errorcodes, wenn man Exceptions bereits in der Sprache zur Verfügung hat? Und ich rede hier von Errorcodes, nicht von einem Bool, oder auch mal einem TriBool, für spezielle Funktionen.

    Ähm tschulligung, aber ich arbeite ja qausi immer mit ErroCodes (als Enum, ich rede hier nicht unbedingt von bool) und hab noch NIE ein goto gebraucht...
    rya.



  • dito.... ich bin seit meinem Wechsel auf C / C++ noch nie auf die Idee gekommen irgendwo rumzuspringen 😃



  • it0101@loggedoff schrieb:

    dito.... ich bin seit meinem Wechsel auf C / C++ noch nie auf die Idee gekommen irgendwo rumzuspringen 😃

    damals in Basic.... naja egal. Vergessen wir dieses dunkle Zeitalter 😉


Anmelden zum Antworten