std::exception und die Kinder



  • Wenn der Aufruf aber mit Benutzereingaben geschieht, so hat das doch nichts mit der Programmlogik zu tun.

    Der Funktion ist es egal woher, die Daten kommen. Sie wirft einfach bei falscher Benutzung, basta. Woher soll den sqrt wissen, woher seine Parameter kommen?

    Wenn du von Amazon ein Paket bekommst und es ist das Falsche drin, dann schickst du es auch zurueck, egal ob es ein Roboter verpackt hat oder ein Mensch.



  • Eigene Exception-Klassen leite ich grundsätzlich von std::runtime_error ab.
    Bei "logic errors" mach' ich keine eigenen Klassen, sondern werfe eine der vom Standard definierten.
    Wenn keine andere passt auch einen std::logic_error direkt.

    Eisflamme schrieb:

    ... die Angabe einer negativen Zahl für eine Wurzelfunktion. Wenn der Aufruf aber mit Benutzereingaben geschieht, so hat das doch nichts mit der Programmlogik zu tun. Wo liegt mein Denkfehler?

    Dein Programm ruft die Wurzelfunktion mit einer negativen Zahl auf, und das ist nicht erlaubt. Daher ist das ein Programmfehler.
    Wenn die Zahl aus einer Benutzereingabe kommt, dann ist der Fehler dass dein Programm die Benutzereingabe nicht validiert bevor er damit die Wurzelfunktion aufruft.



  • dfdf schrieb:

    Ich bin allgemein der Meinung, dass diese Aufteilung und das ganze std::exception-Design schlecht ist.

    Warum? Was insbesondere ist an der Aufteilung in Logik- und Laufzeitfehler schlecht?



  • Ich verstehe das Argument zwar - aber ist der Exceptionwurf nicht genau die Behandlung der Falscheingabe? Was spricht denn dagegen die Exception dann einfach zu fangen und einen Fehler auszugeben, dass die Eingabe falsch war. Wieso nochmal etwas drumherum packen?



  • aber ist der Exceptionwurf nicht genau die Behandlung der Falscheingabe?

    Exceptions haben was mit Ausnahmen zu tun voellig losgeloest von Eingaben.



  • Bashar schrieb:

    Warum? Was insbesondere ist an der Aufteilung in Logik- und Laufzeitfehler schlecht?

    In welchen Situationen kann man std::logic_error denn sinnvoll einsetzen? Das einzig Vernünftige, was man damit tun kann, ist das Programm sofort zu beenden und einen Log o.Ä. zu schreiben. Nach einem Logikfehler sollte man aber nicht weiterarbeiten.

    Ist für mich halt eher ein Fall von assert...



  • Logikfehler werden koennen weiter spezifiziert werden durch domain_error, invalid_argument, length_error, out_of_range, future_error. logic_error ist also genau dann sinnvoll, wenn es so aehnlich wie dessen Ableitungen ist, diese es nicht ganz treffen.

    Nach einem Logikfehler sollte man aber nicht weiterarbeiten.

    Koennen muessen sollen ... ist vom Anwendungs- und Problemfall abhaengig.

    Das einzig Vernünftige ... das Programm sofort zu beenden

    Bullshit.



  • logik0r schrieb:

    Ist für mich halt eher ein Fall von assert...

    assertions haben im Release-Modus keine Wirkung.

    BTW, sollte das eine Antwort auf meine Frage sein? Wenn du der Meinung bist, dass Logikfehler als Exceptions sinnlos sind, dann ist doch nicht die Aufteilung der Exceptionhierarchie schlecht, sondern gerade gut. Du kannst den Zweig logic_error dann ja einfach ignorieren.



  • Was sind für euch Logikfehler? Für mich sind Logikfehler Bugs.

    Etwas, das im Release-Modus nicht vorkommt. Und vor allem etwas, das man nicht sinnvoll zur Laufzeit behandeln kann -- wenn die Programmlogik fehlerhaft ist, wie soll man dann noch weiterarbeiten? Jeder weitere Schritt basiert auf fehlerhaften Annahmen. Man läuft Gefahr, noch mehr Schaden anzurichten, wenn man den Fehler ignoriert. Daher würde ich versuchen, was möglich ist zu retten, und das Programm zu beenden.


  • Mod

    logik0r schrieb:

    Daher würde ich versuchen, was möglich ist zu retten, und das Programm zu beenden.

    Und wie machst du das? Sicherlich nicht, indem du den Fehler ignorierst oder mittels assert ein exit auslöst, sondern indem du eine Exception wirfst, die gefangen wird und einen geregelten Abbruch auslöst.



  • @SeppJ
    Nein, eben gerade nicht.
    Man will eigentlich einen nicht-ganz-so-geregelten Abbruch.
    Ideal wäre die Exception gar nicht zu fangen.

    WENN man denn überhaupt abbrechen will.

    @logik0r
    Die Argumentation ist so alt wie das Thema Fehlerbehandlung in Programmen.
    Der Standpunkt ist nicht unsinnig. Er ist aber auch nicht der einzige der Sinn macht. In vielen Fällen ist es besser das Programm fortzusetzen.



  • Also ich finde "falsches Argument ist ein Logikfehler" nicht konsistent durchdenkbar.

    Demnach sollte eine invalid_argument-Exception nicht ausgelöst werden, wenn der Benutzer irgendwas eingibt?
    ~~
    Wenn mein XML-Parser also eine invalid_argument-Exception wirft, weil der Benutzer in der Datei rumhantiert hat (was er darf!), aber einen Fehler gemacht hat, dann ist das nicht legitim? Analog zur Wurzelfunktion müsste ich ja hier vorher alles prüfen, damit die Exception nicht geworfen wird, weil die ja sagen würde "falsches Argument" und damit ein Logikfehler wäre. Oder habe ich einen Denkfehler?~~

    std::streams kann man so einstellen, dass die bei Falscheingabe eine Exception werfen.

    int x;
    std::cin >> x;
    

    Benutzer gibt "Hund" ein, Exception fliegt => Das ist aber ein runtime_error. Vom Namen her wäre invalid_argument doch die perfekte Basisklasse. Oder ist "Hund" in dem Kontext kein Argument? Dann finde ich aber invalid_argument als Namen irreführend.


  • Mod

    Eisflamme schrieb:

    Oder ist "Hund" in dem Kontext kein Argument?

    Argumente sind das, was an Funktionen übergeben wird, nicht die Zeichen in irgendeinem Stream. Hier also das x.



  • Dann nehme ich doch wieder mein Beispiel mit der XML-Datei. Die lese ich einen string, den übergebe ich meinem Parser. Parser merkt "das ist grober Unfug" und schmeiß ne Exception. Wäre die Exception vom Typ invalid_argument, wäre das für mich vom Namen her korrekt, weil das Argument mit dem Inhalt "XML-Datei" invalide war.

    Wäre aber trotzdem basierend auf Benutzereingabe, hat nichts mit einem Logikfehler der Software zu tun.


  • Mod

    Ist doch egal, woher der Inhalt der Zeichenkette kommt. Letztendlich war das Argument "grober Unfug", das Durchführen der Aktion logisch unmöglich. Der runtime_error zeigt hingegen an "Upps, das sah eigentlich richtig aus, hat aber trotzdem nicht funktioniert".



  • Man läuft Gefahr, noch mehr Schaden anzurichten, wenn man den Fehler ignoriert. Daher würde ich versuchen, was möglich ist zu retten, und das Programm zu beenden.

    Niemand redet von Ignorieren, Abbruch ist die letzte Option, aber nie die einzige. Ein konsistenter Zustand der Anwendung ist bei vielen Programmen gefragt, erst wenn dieser nicht mehr hergestellt werden kann, dann ist ein koordinietes Beenden sinnvoll.



  • Achso. Ich dachte, logical_error hieße, dass die Software einen Logikfehler enthält, nicht etwa dass eine Aktion logisch nicht möglich durchführbar ist. Natürlich sind asserts für ersteres da.

    Nagut, dann... puh, ich weiß nicht, ob ich die Unterscheidung so toll finde. Schließlich ist logical_error ja auch ein Fehler, der zur Laufzeit geschieht, somit eine Art "runtime_error", auch wenn das Wort es nicht bedeutet.

    Mir fällt nicht Besseres ein, aber mir erscheint das einfach überhaupt nicht intuitiv... mein Problem 😉


  • Mod

    Das ist ja auch so eine Art logischer Fehler in der Software, wenn so etwas auftreten kann. Sie hat so geschrieben zu sein, dass unmögliche Aktionen gar nicht erst durchgeführt werden.



  • Find ich nicht. Wenn der Benutzer mir eine malformed XML-Datei eingibt, fliegt dadurch eine Exception, die fange ich und weiß dadurch, dass sie korrupt ist. Dann kriegt der Benutzer eine entsprechende Meldung und das Programm läuft weiter, als hätte man die Datei noch nicht geladen.

    Wieso soll ich da einen großartigen XML-Check vorsetzen? Regel ist, dass die XML-Datei in Ordnung ist. Ausnahme, dass etwas daran kaputt ist, weil der Benutzer Fehler gemacht hat.

    Es ist einfach unnötiger Aufwand irgendwelche Checks drumherum einzubauen, wenn der Parser das selbst macht und mir das mit einer Exception mitteilt. Mehr Code, der fehlerhaft sein kann und der einfach unnötig ist. Genau so sehe ich nicht, wieso ich bei einer Wurzelfunktion nicht einfach die Exception fangen kann, dem Benutzer die Ausgabe gebe, dass das Argument invalide ist und der Ablauf weitergeht... Wo ist das Problem?



  • @Eisflamme
    Einen "logic error" mit einer Exception statt ASSERT/abort/... zu behandeln kann oft in Interfaces zwischen zwei Programmteilen Sinn machen.

    Denk nur mal an Betriebssysteme.

    Ich denke die wenigsten Leute hätten viel Freude damit wenn das OS sämtliche "logic errors" mit einem BSOD bzw. auch nur dem Abbruch des Prozesses quittieren würde.
    Beispielsweise wenn man einen IOCTL an ein Gerät schickt das diesen gar nicht unterstützt.
    Oder wenn man versucht in ein File zu schreiben das man nicht schreiben darf.

    Das sind Dinge die ein Programm immer vermeiden könnte, aber oft ist es besser es einfach zu probieren und dann zu sehen was passiert. Weil es oft viel unkomplizierter umzusetzen ist, und unkomplizierter ist besser als komplizierter.

    Natürlich kann man jetzt sagen dass alles was "von ausserhalb" kommt erstmal validiert werden müsste. Aber es ist oft einfach nicht praktikabel alles vorab erstmal zu validieren. Es ist oft viel praktischer in der Schicht die die Requests von Ausserhalb entgegennimmt nur bestimmte grundlegende Dinge zu validieren, und den Request dann an einen anderen Programmteil weiterzureichen.
    Wenn der dann aber sämtliche "invalid argument" Fehler mit ASSERT/abort quittiert, hat man ein Problem.

    mMn. muss man in jedem Fall einzeln entscheiden ob es OK ist bei einem bestimmten Fehler eine Exception zu werfen, oder ob es doch besser wäre den Prozess einfach abzubrechen.


Anmelden zum Antworten