Error handling: Exception vs. Error return value
-
Ich hab eine frage, die mich schon längere zeit beschäftigt und von der man irgentwie von überall verschiedene meinungen hört.
Die frage befasst sich mit error handling.
Wann sollte eine funktion einen error wert zurückgeben und wann sollte man stattdessen exceptions mit try und catch blöcken verwenden?also entweder:
bool loadFile(const std::string& filename){ bool result = true; /*load*/ return result; } int main(){ if(!loadFile("myfile.txt") std::cout << "error" << std::endl; return 0; }
oder:
void loadFile(const std::string& filename){ bool result = true; /*load*/ if(!result) throw std::exception; } int main(){ try{ loadFile("myfile.txt"); }catch(...){ std::cout << "error" << std::endl; } return 0; }
erster nachteil an return werten:
wenn man zum beispiel einen int wert zurückgibt ist es oft schwer einen wert für den error zu finden der zurückgegeben werden kann, aber das würde sich ja auch leicht lösen lassen:template<typename T> struct optional{ bool ret; T value; }; optional<int> mathOperation(){ optional<int>.ret result = true; /*calculate*/ return result; }
-
Exception, denn meistens möchte ich wenn das Öffnen des Streams nicht klappt, dann klappt der Konstruktor des Images nicht, dann klappt das Erzeugen der Icons nicht, dann klappt das Starten des Games nicht, dann erst will ich dem User anzeigen "Konnte Datei panzer.jpg nicht öffnen." Das qualifiziert bis oben hinzureichgen, wäre mir viel zu mühselig.
-
also angewöhnen generell exceptions zu nutzen?
-
loadFile ist was GANZ anderes als mathOperation! Bei mathOperation normalerweise assert.
-
http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-5.html
Exceptions nutze ich (fast) gar nicht mehr.
-
gamer8o4 schrieb:
also angewöhnen generell exceptions zu nutzen?
Nee, Exceptions besonders sparsam benutzen. Nämlich dicht an den Betriebssystemaufrufen. Die höheren Funktionen kümmern sich meisten um gar nichts, gehen einfach davon aus, daß alles klappt. Wenn nicht, fliegt halt ne Exception durch bis zu irgend jemandem, der sie behandeln kann, meistens ganz hoch zum Benutzer.
Kanns ja nix machen, wenn die Datei nicht da ist. Eine andere Datei laden? Schwarz anzeigen? No, lieber den Benutzer ausschimpfen, daß er endlich die CD wieder einlegt. Und dann darf er nochmal versuchen, auf den StartGame-Button zu klicken, wenn er sich noch traut.
-
loadFile ist was GANZ anderes als mathOperation! Bei mathOperation normalerweise assert.
eine exception die nicht "gecatched" wird hat doch den gleichen effekt, wie assert oder? beide rufen normalerweise abort() auf und schließen das programm
-
gamer8o4 schrieb:
loadFile ist was GANZ anderes als mathOperation! Bei mathOperation normalerweise assert.
eine exception die nicht "gecatched" wird hat doch den gleichen effekt, wie assert oder? beide rufen normalerweise abort() auf und schließen das programm
Spätestens die main() macht catch(...).
-
Kanns ja nix machen, wenn die Datei nicht da ist.
aber ich muss doch irgentwie merken, dass da was falsch gelaufen ist und nicht einfach schön noch nen parser aufrufen und und und bis ich mich irgentwann noch tiefer in die scheiße geritten habe anstatt mal eben schnell ne messagebox auszugeben?
-
gamer8o4 schrieb:
Kanns ja nix machen, wenn die Datei nicht da ist.
aber ich muss doch irgentwie merken, dass da was falsch gelaufen ist und nicht einfach schön noch nen parser aufrufen und und und bis ich mich irgentwann noch tiefer in die scheiße geritten habe anstatt mal eben schnell ne messagebox auszugeben?
Die Exception fligt doch durch deine Funktion hoch und bricht sie ab. Da wird kein Parser mehr aufgerufen. Die Messagebox wird in der main oder irgendwo oben angezeigt. Nich da in der Mitte bei Dir gerade. Und sie kommt von weit unten, einem loadFile oder so.
-
assert
ist für Logikfehler. Im Release-Modus wird es wegoptimiert.Logikfehler treten nur bei fehlerhafter Programmierung auf. Du kannst sie nicht sinnvoll behandeln, weil es gar nie so weit kommen dürfte. Daher hält
assert
unmittelbar den Debugger an, sodass du den Fehler auch sicher nicht übersiehst.
-
okay, habs kapiert
aber nochmal um das klarzustellen, einen bool wert als fehler zurückzugeben ist unpraktisch!?
-
wo, außer bei IO, verwendet ihr exceptions?
-
assert ist für Logikfehler.
also das macht assert das gleiche wie "throw std::logic_error("fehler");"
Im Release-Modus wird es wegoptimiert.
Logikfehler treten nur bei fehlerhafter Programmierung auf. Du kannst sie nicht sinnvoll behandeln, weil es gar nie so weit kommen dürfte. Daher hält assert unmittelbar den Debugger an, sodass du den Fehler auch sicher nicht übersiehst.merke ich mir
-
gamer8o4 schrieb:
okay, habs kapiert
aber nochmal um das klarzustellen, einen bool wert als fehler zurückzugeben ist unpraktisch!?So ist es fast immer, ja.
-
cooky451 schrieb:
http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-5.html
Exceptions nutze ich (fast) gar nicht mehr.wo, außer bei IO, verwendet ihr exceptions?
IO ist ein Parade-Gegenbeispiel was Exceptions angeht. Sobald man nämlich asynchrone Aufrufe hat, geht da nichts mehr. Bei jedem ernsthaften Programm kann man heutzutage mehrere I/O Aufrufe gleichzeitig haben, das betrifft Files, Sockets, etc. pp., wenn einem da überall Exceptions um die Ohren fliegen würden könnte man hinten und vorne nichts mehr sehen.
-
pumuckl hat mal einen guten Beitrag dazu geschrieben.
-
dirtydynamite schrieb:
wo, außer bei IO, verwendet ihr exceptions?
Wenn ich mal nicht faul bin eigentlich bei jedem Betriebssystemaufruf oder Fremdbibliotheksaufruf, der irgendwie nicht klappen könnte. Socket geht nicht zu öffnen, ein Font geht nicht zu holen, eine Memory-Mapping geht nicht auf, ein Timer kann nicht erzeugt werden, read, write, recv, setSignal, schlägt fehl...
Naja, meistens bin ich ein wenig zu faul. Aber eigentlich sollte ich jede fremde fehlschlaganzeigende Funktion wrappen durch eine, die bei Fehlschlag eine Exception wirft.
-
gamer8o4 schrieb:
also das macht assert das gleiche wie "throw std::logic_error("fehler");"
Nein, kein bisschen.
throw
wirft eine Exception.assert
prüft eine Bedingung und reklamiert im Debug-Modus sofort, falls siefalse
ist.Was
std::logic_error
angeht, ich verwende diesen Exceptiontypen aus den vorher genannten Gründen nicht. Würde mich interessieren, was andere dazu meinen...
-
cooky451 schrieb:
cooky451 schrieb:
http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-5.html
Exceptions nutze ich (fast) gar nicht mehr.wo, außer bei IO, verwendet ihr exceptions?
IO ist ein Parade-Gegenbeispiel was Exceptions angeht.
Eben, darum nicht nochmal aufzählen.
volkard schrieb:
Socket geht nicht zu öffnen, ein Font geht nicht zu holen, eine Memory-Mapping geht nicht auf, ein Timer kann nicht erzeugt werden, read, write, recv, setSignal, schlägt fehl...
Auch fast alles IO, außer Timer.