Exceptions (Design-Frage)



  • Hallo zusammen,

    wo sollten eigene Exception-Klassen deklariert werden? Ist es bei Klassen-spezifischen Ausnahmen sinnvoll, diese im entsprechenden Headerfile der Klasse zu deklarieren?

    Wie organisiert Ihr die Exceptions in Namensräumen? z.B. ein gemeinsamer Namensraum "MyExceptions"? Wie handhabt Ihr es bei Bibliotheken?

    Viele Grüße

    Roger Wilco



  • Roger Wilco schrieb:

    Hallo zusammen,

    wo sollten eigene Exception-Klassen deklariert werden? Ist es bei Klassen-spezifischen Ausnahmen sinnvoll, diese im entsprechenden Headerfile der Klasse zu deklarieren?

    Deklarieren nützt da nicht viel, aber vielleicht meinst du ja auch definieren. Ich machs mal so, mal so. In meinem aktuellen Projekt gibts 4 oder 5 Klassen, die die eigentliche API für mein Framework bilden. Dort steht nur in den Doku-Kommentaren (ich nutze doxygen), welche Exceptions fliegen können. Die Exception-Klassen selbst sind nicht in den Headern enthalten. Schließlich muss/kann der Anwender nicht in der selben Source Exceptions behandeln, in der er auch die werfenden Funktionen aufruft. Ich hab einen extra Header "MyXYExceptions.h", in dem ich die 5-10 möglichen Exceptions definiere. Der Anwender kann den Header dann dort einbinden, wo er die Exceptions auch fangen und behandeln kann/will.

    Wie organisiert Ihr die Exceptions in Namensräumen? z.B. ein gemeinsamer Namensraum "MyExceptions"? Wie handhabt Ihr es bei Bibliotheken?

    Die Exceptions liegen bei mir im gleichen Namensraum wie die Klassen. Ich hab allerdings wie beschrieben nur sehr wenige Klassen im Interface des Frameworks und entsprechend wenige Exceptions. Btw: Die Exceptions sind alle von einer bzw. zwei gemeinsamen Exception-Basisklassen abgeleitet. Die wiederum leiten von std::logic_error und std::runtime_error ab.



  • Hallo pumuckl!

    pumuckl schrieb:

    Deklarieren nützt da nicht viel, aber vielleicht meinst du ja auch definieren.

    Ja, meinte ich. Ich habe mir den Unterschied eben noch einmal angelesen. Danke für den Hinweis!

    pumuckl schrieb:

    Ich hab einen extra Header "MyXYExceptions.h", in dem ich die 5-10 möglichen Exceptions definiere. Der Anwender kann den Header dann dort einbinden, wo er die Exceptions auch fangen und behandeln kann/will.

    Das war auch mein Gedanke/Ansatz.

    pumuckl schrieb:

    Die Exceptions liegen bei mir im gleichen Namensraum wie die Klassen.

    Alle Exceptions im (Haupt/Basis-)Namensraum der Bibiothek/des Projektes oder auch in den (Unter-)Namensräumen der gesamten Hierarchie? Was wenn eine Exception aus mehreren Klassen geworfen werden kann und diese beiden Klassen in unterschiedlichen Namensräumen sind?



  • Roger Wilco schrieb:

    Alle Exceptions im (Haupt/Basis-)Namensraum der Bibiothek/des Projektes oder auch in den (Unter-)Namensräumen der gesamten Hierarchie?

    Ich hab einen (Haupt-)Namensraum, in dem die API der Bibliothek liegt. Alle anderen Namensräume sind interne Implementatonsdetails und liegen unter dem Hauptnamensraum. Die Exceptions, die aus der API geworfen werden können, liegen auch im Hauptnamensraum. Wenn ich weiter unten irgendwelche speziellen Exceptions werfe, übersetze ich sie, so dass die Bibliothek nur die Exceptions aus dem Hauptnamensraum wirft.



  • pumuckl schrieb:

    Die Exceptions sind alle von einer bzw. zwei gemeinsamen Exception-Basisklassen abgeleitet. Die wiederum leiten von std::logic_error und std::runtime_error ab.

    Ich dachte, std::logic_error und std::runtime_error widersprechen einander. Kannst du nochmal genauer sagen, wie du das machst?



  • runlo schrieb:

    pumuckl schrieb:

    Die Exceptions sind alle von einer bzw. zwei gemeinsamen Exception-Basisklassen abgeleitet. Die wiederum leiten von std::logic_error und std::runtime_error ab.

    Ich dachte, std::logic_error und std::runtime_error widersprechen einander. Kannst du nochmal genauer sagen, wie du das machst?

    Ich glaube pumuckl hat zwei eigene Basisklassen für seine Ausnahmen. Eine davon ist von std::logic_error und die andere von std::runtime_error abgeleitet.

    pumuckl schrieb:

    Wenn ich weiter unten irgendwelche speziellen Exceptions werfe, übersetze ich sie, so dass die Bibliothek nur die Exceptions aus dem Hauptnamensraum wirft.

    Tust Du dies grundsätzlich. Also auch mit std-Exceptions?



  • Roger Wilco schrieb:

    runlo schrieb:

    pumuckl schrieb:

    Die Exceptions sind alle von einer bzw. zwei gemeinsamen Exception-Basisklassen abgeleitet. Die wiederum leiten von std::logic_error und std::runtime_error ab.

    Ich dachte, std::logic_error und std::runtime_error widersprechen einander. Kannst du nochmal genauer sagen, wie du das machst?

    Ich glaube pumuckl hat zwei eigene Basisklassen für seine Ausnahmen. Eine davon ist von std::logic_error und die andere von std::runtime_error abgeleitet.

    Richtig.

    pumuckl schrieb:

    Wenn ich weiter unten irgendwelche speziellen Exceptions werfe, übersetze ich sie, so dass die Bibliothek nur die Exceptions aus dem Hauptnamensraum wirft.

    Tust Du dies grundsätzlich. Also auch mit std-Exceptions?

    Das ist ne Designfrage, die ich noch nicht ganz geklärt habe. Es macht imo wenig Sinn, einen std::bad_alloc eins zu eins in ein myframework::bad_alloc umzumodeln. Dadurch hat man wenig Gewinn. Wenn ich aber beim Initialisieren meines Servers einen bad_alloc oder eine andere Standard-Exception fange und die, egal was kommt, in eine allgemeinere ServerException("Initialization error") umwandle ist das was anderes.



  • Danke pumuckl für Deine Antworten.

    Eine weiterführende Frage zum Thema Multithreading und Fehlerbehandlung:

    Ich habe eine Schnittstelle, bei der der Aufrufer einen Ergebnis-Handler registriert. Dieser wird dann aufgerufen, sobald das Ergebnis vorliegt.

    Nun möchte ich auch Fehler an den Aufrufer melden. Mein Ansatz wäre jetzt, dass der Aufrufer einen seperaten ErrorHandler dafür registriert (anstatt das über den Ergebnis-Handler via zusaätzlichen Error-Parameter mit zu erschlagen).

    Ich bin mir nun nicht sicher, ob ich bei Aufruf des ErrorHandlers auch Exceptions, andere Fehler-Klassen oder Fehlercodes übergeben soll.



  • Darf ich nochmal nachfragen:

    • Ist das Konzept mit einem extra Error-Handler sinnvoll? Nachteil wäre, dass der Aufrufer zwei Handler registrien müsste. Voteil wäre, dass man keine Fallunterscheidung im Ergebnis-Handler machen muss.
    • Was sollte an den Error-Handler übergeben werden? Exceptions? Objekte einer seperaten Fehlerklasse explizit für den Error-Handler? Error-Codes?

    Fehler die auftreteten könnten:

    • Fehler bei der Kommunikation (Socket-Fehler)
    • Fehler durch Bug auf Serverseite
    • Fehler, die im Protokoll definiert sind

    Ich würde mich über Hinweise und Empfehlungen von Euch freuen. Ich bin mir nicht sicher, was guter Stil wäre oder einfach sinnvoller wäre.


Anmelden zum Antworten