std::exception und die Kinder



  • Hi,

    ich wollte jetzt Mal brav meine Klasse von std::exception erben lassen. Bei vielen Stackoverflow-Beiträgen stand aber, man sollte doch lieber von den Unterklassen erben.

    Jetzt verstehe ich diese aber nicht. std::runtime_error und std::logical_error wären für mich jetzt per se erstmal exklusiv, das geht klar. Aber von std::logical_error erbt ja wiederum std::domain_error und als Beispiel dafür steht bei cplusplus.com/reference ( http://www.cplusplus.com/reference/stdexcept/domain_error/ ) 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?

    Beste Grüße!



  • Eisflamme schrieb:

    Wenn der Aufruf aber mit Benutzereingaben geschieht, so hat das doch nichts mit der Programmlogik zu tun. Wo liegt mein Denkfehler?

    logic_error sagt dir, dass die Programmlogik die Benutzereingabe vorher auf <0 hätte checken sollen. Programme, die sqrt(negativeZahl) aufrufen, fehlt dieser notwendige Check.

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



  • 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.


Log in to reply