Elegante weitergabe von Exceptions

Gast #6019547
Lesenswert?

Moin,

ich wechsel gerade (zumindest teilweise) von der Embedded 
C-Programmierung zu C++. Diese Frage gehört bestimmt zum 
Grundrepertoire.

In C habe ich bisher z.B. eine Funktion gehabt:
1
int irgendwas(){
2
}

Diese hat neben dem Ergebnis auch Fehlercodes übertragen (z.B. -1, -2, 
etc..). Wenn ich nun eine Funktion habe, die nur true/fase zurückliefern 
soll, jedoch auch Fehler weil z.B. eine Datei nicht geöffnet werden 
könnte, möchte ich das nun sinnigerweise übr try/catch lösen.

Wie formatiere ich nun elegant und praxisorientiert diese Fehler? Soll 
ich in der Funktion lauter "throws" einsetzen? Sollen diese Fehlercodes 
oder Strings zurückliefern? Und wenn ich die Funktion "irgendwas" 
aufrufe innerhalb eines try/catch blocks, gebe was mache ich mit dem 
Fehler?

Ok, was ich damit anstelle ist meine Sache (speichern, ausgeben, 
verwerfen, etc.) aber ich  frage mich, ob meine Herangehensweise richtig 
ist oder ich das Konzept nicht ganz richtig verstanden habe. Sollte ich 
z.B. Fehlercodes zurückgeben, muss ich diese wieder irgendwo definieren, 
was ich mir ziemlich umständlich vorstelle.

Danke!
Gast #6019581
Lesenswert?

throw ist nicht schlecht
aber manchmal gibt es auch lässliche Fehler
und du möchtest die laufende Routine deswegen noch nicht sofort 
unterbrechen;
dann könntest Du eine eignene Fehlerbehandlung implementieren
wie:
void dontThrowThisErrorJustYet(int fehlercode, std::string 
fehlermeldung)

das schreibt dann zB ein Logfile oder speichert die Warnungen (sind ja 
mehr oder weniger solche) für einen späteren Gebrauch.

Gespeichertes wieder hervorzaubern zu einem günstigen Zeitpunkt kannst 
Du ja immernoch

Und die Frage ob Du code oder Meldung willst beantwortet sich relativ 
einfach
User haben sich daran gewöhnt beides zu sehen,
Informativer ist aber meist eine ausssagekräftige FehlerMELDUNG.

Ein FehlerCODE ist nützlicher für den Programmierer,
manches lässt sich innerhalb des Codes reparieren und braucht 
nichteinmal Nutzerintervention,
das kann dann über eine int leichter identifiziert werden als über einen 
string intern.

Ausserdem hilft code bei der Auffindung innerhalb des Quelltextes
(001265 .. datei 0012 Routine 6 Fehleroption 5 zB)
oder man macht sich selbst Regeln
(001265 00 user input, 12 formatting error, 6 numerical, 5 dateformat)

Was das gliedern in Tabellen und die damit verbundenen übersetzung in 
FehlerMELDUNGEN erleichtert.

Was die lieber ist und womit Du Dich wohler fühlst ist Dir überlassen.
(ich benutz mal so mal so um ehrlich zu sein)
#6019603
Lesenswert?

Eine der wichtigsten Grundregeln ist sich für eine der beiden Varianten 
zu entscheiden. Entweder man bleibt (z.B. wegen Performance) bei 
klassischen Fehlercodes bzw. Varianten davon (siehe std::expected) oder 
man setzt auf Exceptions.

Da Exceptions in den meisten Fällen Domain-spezifisch sind bleibt es dir 
überlassen wie du die gestaltest. Die meisten Exceptions in der 
Standardbibliothek enthalten Strings, manche Enums und manche überhaupt 
komplett andere Typen die in dem Context allerdings Sinn machen (C++20 
nonexistent_local_time etwa).

Folgender CppCon Talk fasst ganz gut zusammen worauf man achten sollte:
https://www.youtube.com/watch?v=W6jZKibuJpU
Gast #6025480
Lesenswert?

So wie es aussieht geht hier die Meinung ja eher zum klassischen 
Fehlercode.
Packe ich dann mein ENUM mit den sprechenden Codes in z.B. meine Klasse 
unter public?

Vermutlich wrde ich es so lösen, dass gravierende Probleme als throw 
zurückgeworden werden und inhaltliche Probleme mit einem enum behandelt 
werden als normaler Rückgabewert. Ist das ein eleganter Lösungsweg?
#6025486
Lesenswert?

Jens schrieb:
> So wie es aussieht geht hier die Meinung ja eher zum klassischen
> Fehlercode.

Ich denke eher: it depends.

Mache Dir klar, was Du unter "Fehler" verstehst. Z.B. ist die leere 
Menge beim Suchen kein Fehler im engeren Sinn, sondern ein ganz normales 
Ergebnis. In dieser Art gibt es viele Operationen. Manchmal hat man die 
Möglichkeit, für diesen Fall sog. invalide Objekte zurückzugeben. Oder 
man nimmt std::optional<> und externalisiert den ungültigen Zustand des 
Objektes.

Nur bei echten, tragischen Fehlern, die auch wahrscheinlich mit geringer 
Häufigkeit vorkommen, werden dann Ausnahmen verwendet.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren