C++ Exceptions und Relevanz
-
expected<useless> schrieb:
Wers noch nicht kennt: http://en.cppreference.com/w/cpp/experimental/optional
Wenn du den Vortrag tatsächlich gesehen und verstanden hättest, würdest du wissen, dass er dort auch auf
boost::optionaleingeht (was de facto dasselbe ist) und wüsstest, was der Unterschied zuExpected<T>ist.Einfach ausgedrückt: wenn du irgendwo in deinem Code, fernab der Funktion, die den Wert gesetzt hat einen
optional<T>in die Hand gedrückt bekommst und dieser keinen "value" hat, obwohl er einen haben müsste, woher weisst du dann was schiefgelaufen ist?Und wenn du ein Kopzept schon durch deine Namenswahl implizit als nutzlos bezeichnest, dann kann ich das nur dann akzeptieren, wenn du das auch zumindest ansatzweise begründest (lasse mich immer gerne überzeugen wenn es einleuchtet). Behauptungen aufstellen und einen sinnlosen Link posten ist da leider etwas zu wenig.
Finnegan
-
happystudent schrieb:
Shade Of Mine schrieb:
Weil man höllisch aufpassen muss. Ein zu aggresives catch irgendwo killt dir den ganzen Mechanismus und ist quasi nicht auffindbar.
Das geht aber nur mit einem
catch(...)(der Typ des geworfenen Objekts ist schließlich weggekapselt und nicht sichtbar). Und wenn man nach einemcatch(...)nicht re-throwt ist man ja wohl selbst schuld bzw. hat eh ganz andere Probleme.Achnene, da hat Shade schon Recht.
catch (...)ohne re-throw ist das was man manchmal einfach braucht.
Dummerweise.
Wenn die Welt schön rosa wäre, und alle "normalen" Exception-Klassen vonstd::exceptionabgeleitet wären, dann wäre es 'was anderes. Ist aber leider nicht so. Es gibt immer noch tonnenweise Libraries die eigene Exception-Klassen verwenden die nicht vonstd::exceptionabgeleitet sind.
Weil die Library entwickelt wurde als C++ noch nicht ordentlich standardisiert war, weil die Library von jemandem entwickelt wurde der sich nicht im Klaren darüber war was er damit anrichtet, weil von solchen Libraries "abgeschrieben" wurde ...Und es gibt dummerweise auch Stellen wo man ein "egal was schiefgegangen ist, hier stellen wir jetzt fest dass wir nicht machen konnten was wir machen wollten, und machen dann mit dem restlichen Programm weiter" braucht.
An diesen Stellen dann jeweils 5+ catch Blöcke zu schreiben ist einfach nicht praktikabel. Und im Endeffekt hat man dann eine Exception-Klasse übersehen, und ist erst wieder angeschmiert.BTW: Den Typ des geworfenen Objekts kann man sich mittels re-throw in einer geeigneten Hilfsfunktion, die dann die dutzenden verschiedenen catch-Blöcke enthält, die man sonst an 1000 Stellen schreiben müsste, besorgen.
Ich hab' da z.B. eineGetErrorMessageFromCurrentException()und eineLogCurrentException()Hilfsfunktion.
Und eine Guard-Klasse die sich um so gottlose Drecksklassen wieCException(MFC) kümmert -- damit am Ende des catch-Handlers dann auche->Delete()aufgerufen wird.
Exception beliebigen Typs fangen + loggen + ggf. entsorgen (CException) beschränkt sich damit auf//... catch (...) { CleanupExceptionGuard guard; LogCurrentException(); }ps: Und
catch (...)mit re-throw ist ja nun wirklich bäh. Dafür baut man sich passende Hilfsklassen. Im Falle des Falles, also wenn es in einem Programm wichtig ist, kann man dann nämlich Code-Teile ohne äusserescatchlaufen lassen, und die darin auftretenden Exceptions die niemand fangen mag von einem Crash-Handler verarbeiten. Der kann dann einen Dump schreiben wo das Programm genau in dem Zustand ist wo die Exception geworfen wurde. Nicht 10 Levels tiefer im Callstack wo ein blödescatch (...)mit re-throw steht, und man schon keinen Anhaltspunkt mehr hat wo die Exception überhaupt entstanden ist.
In Anwendungscode mag das jeder halten wie er es für richtig hält. In Libraries hat eincatch (...)mit re-throw meiner Meinung nach aber genau nichts verloren.
-
hustbaer schrieb:
BTW: Den Typ des geworfenen Objekts kann man sich mittels re-throw in einer geeigneten Hilfsfunktion, die dann die dutzenden verschiedenen catch-Blöcke enthält, die man sonst an 1000 Stellen schreiben müsste, besorgen.
In der Präsentation von Andrei Alexandrescu (Folie 26) gibt es ein lustiges Konstrukt:
template<class E> bool hasException() const { try { if(!gotHam) std::rethrow_exception(spam); } catch(const E& object) { return true; } catch (...) { } return false; }Darauf wäre ich wohl nicht so schnell gekommen...
-
hustbaer schrieb:
Achnene, da hat Shade schon Recht.
catch (...)ohne re-throw ist das was man manchmal einfach braucht.
Dummerweise.Ja, ist halt dann ein hack mit dem man sich jede Menge anderer Probleme einhandeln kann.
Weiß nicht, so ganz überzeugt mich diese Argumentation noch nicht:
hustbaer schrieb:
An diesen Stellen dann jeweils 5+ catch Blöcke zu schreiben ist einfach nicht praktikabel. Und im Endeffekt hat man dann eine Exception-Klasse übersehen, und ist erst wieder angeschmiert.
Muss man ja auch nicht? Vor allem wenn man sich eh schon die Mühe macht:
hustbaer schrieb:
BTW: Den Typ des geworfenen Objekts kann man sich mittels re-throw in einer geeigneten Hilfsfunktion, die dann die dutzenden verschiedenen catch-Blöcke enthält, die man sonst an 1000 Stellen schreiben müsste, besorgen.
Schreibt man sich halt eine kleine Hilfsfunktion die die Exceptions entsprechend um-wrappt. Dann muss man nicht "an 1000 Stellen" die catches schreiben, sondern genau einmal und hat danach eine saubere Möglichkeit mit der Library zu arbeiten?
template <typename CodeSegment> void wrap_ugyl_library(CodeSegment cs) { try { cs(); } catch (exception_1 const &) { /* wrap ugly exceptions here */ } catch (int) {} catch (std::string) {} // ... etc. } // ... void run_impl() { ugly_library_function_1(); ugly_library_function_2(); ugly_library_function_3(); } void run() { try { wrap_ugyl_library([&] { run_impl(); }); } catch (std::exception const &wrapped_exception) { std::cerr << wrapped_exception.what() << '\n'; } }
-
@happystudent
Du siehst den Code ernsthaft als Alternative? Ich nicht, sorry.
Dafür ist die Lambda-Syntax zu hässlich.
Programmierst du so, oder ist das einfach nur Apologetik?Und an den vielen Programme die vor 2011 entwickelt wurden (bzw. wo die Entwicklung vor 2011 begonnen hat), und die noch jahrelang weiter entwickelt/supportet werden müssen ändert es auch nix.
-
hustbaer schrieb:
@happystudent
Du siehst den Code ernsthaft als Alternative? Ich nicht, sorry.
Dafür ist die Lambda-Syntax zu hässlich.
Programmierst du so, oder ist das einfach nur Apologetik?Hm, ich find die Lambda Syntax eigentlich sehr gut muss ich sagen. Also ja, ich programmiere so

Bietet sich ja auch in der std-lib oft genug an:
std::sort(vec.begin(), vec.end(), [](my_obj const &left, my_obj const &right) { return left.value < right.value; });Ist ja quasi das selbe, dachte genau für solche Geschichten sind Lambdas da. Man kann das ja auch anders schreiben:
execute_safe([&]{ func(); }); // bzw. ohne captures: execute_safe(func);Find jetzt nicht dass das schlecht aussieht. Ich mag die Syntax, hab aber den Fall auch gar nicht weil ich (bis jetzt) noch keine libs verwendet habe die mit unbekannten Objekten um sich throw-en.
Das Problem könnte man ja durch die Einführung einer Art
std::auto_rethrow_exceptionlösen, damit könnte man dann die C#ThreadAbortExceptionimitieren.Aber ich geb zu dass die Methode nicht 100% Wasserdicht ist.
-
happystudent schrieb:
Hm, ich find die Lambda Syntax eigentlich sehr gut muss ich sagen. Also ja, ich programmiere so

Du schreibst genau solche "mach mal X innerhalb eines try-catch" Funktionen? Hm. Naja, gut, sicherlich auch viel Gewohnheitssache. In C# mach ich ähnliche Sachen ja auch. Vielleicht würde ich mich schnell daran gewöhnen wenn ich einen C++ Compiler hätte der nicht Jahre bevor C++11 rauskam schon sein letztes Service Pack bekommen hat.
happystudent schrieb:
Ich mag die Syntax, hab aber den Fall auch gar nicht weil ich (bis jetzt) noch keine libs verwendet habe die mit unbekannten Objekten um sich throw-en.
Von unbekannten Objekten hat ja keiner was gesagt. Bloss von Klassen die nicht von
std::exceptionabgeleitet sind.Was mir auf die Schnelle so einfällt:
MFCCException*
ATLCAtlException
MSVC_com_error
Xerces-C++SAXException
Xerces-C++DOMException(ist natürlich nicht verwandt mitSAXException)
Crypto++ [c]Exception[/c]
-
Bist du dir bei Crypto++ sicher? http://www.cryptopp.com/docs/ref/cryptlib_8h_source.html#l00110
-
Haha, nein, danke für die Korrektur

(Ich hab doof wie ich bin nur im Doxygen geguckt, und da wird die Basisklasse std::exception halt verschwiegen - weil Doxygen wohl konfiguriert wurde externe Klassen hier zu ignorieren.)
ps: Hab jetzt auch Xerces noch nachkontrolliert, da stimmt es aber (zumindest bei der Version die wir im Einsatz haben).
-
Hab mich auch erst gewundert und dann im Code nachgesehen, wenn es so wäre, dann müssten mir ja jede Menge Exceptions durch die Lappen gegangen sein...
-
happystudent schrieb:
Shade Of Mine schrieb:
Weil man höllisch aufpassen muss. Ein zu aggresives catch irgendwo killt dir den ganzen Mechanismus und ist quasi nicht auffindbar.
Das geht aber nur mit einem
catch(...)(der Typ des geworfenen Objekts ist schließlich weggekapselt und nicht sichtbar). Und wenn man nach einemcatch(...)nicht re-throwt ist man ja wohl selbst schuld bzw. hat eh ganz andere Probleme.Du kannst auch eine andere Exception werfen

Ist halt dann bloed wenn der Code urspruenglich nicht darauf ausgelegt wurde Abort Exceptions korrekt zu handeln.
Shade Of Mine schrieb:
Prinzipiell ist es ein goto und das hat eben gewisse Nachteile.
Ich finde es ist eigentlich eher ein allgemeineres
return, wobei das geworfene Objekt der Rückgabewert ist.nein, es ist ein astreines goto.
Du springst zu einem label (catch) dass irgendwo ist und lustigerweise sogar mehrmals vorkommen kann.
Man verwendet es, weil die alternativen auch nicht super sind. Aber man muss sich immer vor Augen halten: es ist Missbrauch von Exception.