Exceptions ... brauche Hilfe



  • Hi zusammen,

    beschäftige mich gerade mit Exceptions und hab noch ein paar Fragen:

    1. Sollte ich generell immer eine extra Exception-Klasse deklarieren die ich von std::exception bzw. std::runtime_error ableite? Wenn nicht, wann?

    2. Irgendwelche guten Artikel/Blogposts die sich damit beschäftigen?

    3. Angenommen ich habe eine Klasse mit keinem Defaultkonstruktor, welche aber in einem ihrer anderen Konstruktor(en) eine Exception werfen kann. Ich habe dann das Problem, dass das instanziierte Objekt im Scope des try-Blocks ist und danach an Gültigkeit verliert. Wie kann man das handlen ohne jeden Code der danach kommt und in dem das Objekt benötigt wird auch in den try-Block zu fassen?



  • http://www.youtube.com/watch?v=N9bR0ztmmEQ , Teil 2 findest du hoffentlich alleine. Ansonsten noch das Video zu ScopeGuard ... finds jetzt aber nicht.

    1. Sollte ich generell immer eine extra Exception-Klasse deklarieren die ich von std::exception bzw. std::runtime_error ableite?

    Warum solltest du ableiten, wenns std::runtime_error auch tut?

    1. Angenommen ich habe eine Klasse mit keinem Defaultkonstruktor, welche aber in einem ihrer anderen Konstruktor(en) eine Exception werfen kann. Ich habe dann das Problem, dass das instanziierte Objekt im Scope des try-Blocks ist und danach an Gültigkeit verliert. Wie kann man das handlen ohne jeden Code der danach kommt und in dem das Objekt benötigt wird auch in den try-Block zu fassen?

    Wo ist der Sinn davon, ausserhalb des try-Blocks auf das Objekt zugreifen zu wollen? Wenn es movable ist, dann kannst du es herausmoven. placement new und (schlaue) Zeiger bieten weitere Moeglichkeiten. Ein einfaches return auch.


  • Mod

    Warum solltest du ableiten, wenns std::runtime_error auch tut?

    Der Typ des Exception-Objekts repräsentiert den Fehler. runtime_error ist nicht konkret genug. Daher macht es in einigen Fällen Sinn, Exception-Klassen selber zu definieren.

    Edit: Terminologie korrigiert.



  • runtime_error ist nicht konkret genug

    Darunter verstehe ich, dass es runtime_error eben nicht tut. Ich wollte folgende Frage beantworten:

    Sollte ich generell immer eine extra Exception-Klasse deklarieren

    Konkret: Generell und immer fordern als Antwort meistens ein NEIN.



  • Von std::runtime_error zu erben selten richtig schön; die meisten Fehler, die man so hat, passen eher zu std::logic_error -- wenn man sich in diese Hierarchie einfügen will.

    Jetzt ist die Trennung dieser beiden Klassen dummerweise im Standard wenig konkret bzw. missverständlich. Da heißt es:

    ISO/IEC 14882:2011 19.2.1 (11) schrieb:

    The class logic_error defines the type of objects thrown as exceptions to report errors presumably detectable before the program executes, such as violations of logical preconditions or class invariants.

    und

    ISO/IEC 14882:2011 19.2.1 (11) schrieb:

    The class runtime_error defines the type of objects thrown as exceptions to report errors presumably detectable only when the program executes.

    Damit scheint es, als sei logic_error eigentlich kaum zu gebrauchen, wo es doch static_assert gibt, bis man einen Blick in die Vererbungshierarchie der Standardausnahmen wirft: von logic_error abgeleitet sind

    domain_error
    invalid_argument
    length_error
    out_of_range

    von runtime_error sind es

    range_error
    overflow_error
    underflow_error

    ...und wen das zunächst nicht verwirrt, bei dem möchte ich gerne in die Lehre gehen. Gemeint ist etwa Folgendes:

    Fehler wie der Zugriff auf Elemente hinter dem Ende eines Vektors sind Fehler in der Programmlogik (mit einiger Sicherheit Bugs), die vom Programmierer behoben werden können -> logic_error .

    Eingabefehler wie nicht vorhandene Dateien, korrupte Datenbanken oder völlig kaputte Benutzereingaben sind prinzipiell vor Laufzeit des Programms oder zumindest des Programmteils erkennbar. Der Benutzer hätte sicherstellen können, dass die Datei vorhanden ist, dass die Datenbank in Ordnung ist, sich seine Eingaben vorher genauer ankucken können. Es handelt sich um Logikfehler in dem Sinne, dass Vorbedingungen, auf die die Programmlogik sich verlässt, nicht erfüllt sind -> logic_error .

    Berechnungsfehler wie Overflows, Float-Divisionen mit unendlich/nan als Ergebnis oder nicht konvergierende Suchverfahren sind prinzipiell nicht vor der Berechnung erkennbar -> runtime_error .

    Wie sinnvoll diese Klassifizierung im Einzelfall ist, ist nicht allgemein zu beantworten; wenn sie es wäre, wäre meine Antwort wohl in der Umgebung von "nicht sehr". Sie ist leider ziemlich schwammig, so dass nicht immer eindeutig zu sagen ist, wo eine Fehlerklasse einzuordnen ist, und die Unterscheidung, ob ein Fehler vor der Laufzeit hätte erkannt werden können, ist in meiner Erfahrung eine, die recht selten in catch-Blöcken gebraucht wird. Bei mir endet die Sache meistens damit, dass ich mir eine eigene Exception-Basisklasse von std::exception ableite und logic_error und runtime_error links liegen lasse. Wenn man wollte, könnte man beide Welten vereinen, indem man multiple Vererbung benutzt, aber...nein1.

    1wenn man keinen wirklich guten Grund dafür hat.



  • Nachtrag: Jetzt hab ich bei den Quellenangaben Mist gebaut. Zitiert sind 19.2.1 (1) und 19.2.6 (1).



  • und wen das zunächst nicht verwirrt, bei dem möchte ich gerne in die Lehre gehen.

    Logische Fehler entstehen, wenn du den Vertrag bzgl. der Funktion nicht einhaelts. D.h. wenn bspw. als Voraussetzung gefordert wird, dass ein Polygon konvex ist, kann das schlecht als static_assert abgefangen werden, wenn die Information nicht im Typ kodiert wurde.

    Laufzeitfehler sind bspw. wenn jemand das USB-Kabel zu meinem Device zieht waehrend ich Daten uebertrage.

    multiple Vererbung

    Die Uebersetzung hoert sich komisch an.


Log in to reply