Forum: PC-Programmierung Elegante weitergabe von Exceptions


von Jens (Gast)


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!

von DPA (Gast)


Lesenswert?

Jens schrieb:
> Soll ich in der Funktion lauter "throws" einsetzen? Sollen diese Fehlercodes
> oder Strings zurückliefern?

Die sollten Exceptions liefern. Am besten abgeleitet von einer von 
diesen: 
https://stackoverflow.com/questions/11938979/what-exception-classes-are-in-the-standard-c-library

von sid (Gast)


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)

von Vincent H. (vinci)


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

von versus (Gast)


Lesenswert?

Es gibt nur eine Grund für Exceptions, Konstruktoren bei denen ein 
Fehler auftreten kann. Alles andere kann man herkömmlich abfangen und 
sollte es auch.

von Carl D. (jcw2)


Lesenswert?

Eher mittelfristig zu sehen:
https://www.youtube.com/watch?v=ARYP83yNAWk
Herb Sutter referiert über ein Konzept den Komfort von Exceptions mit 
der Performance von ErrorCodes zu vereinen. Aber vor C++23 wird das 
nichts.

von Jens (Gast)


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?

von Wilhelm M. (wimalopaan)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.