Fehler markieren; Exceptions, return-Codes oder Error-Attribut?
-
hustbaer schrieb:
Naja, gibt schon Unterschiede zwischen throw() und noexcept.
Bei throw() war vorgeschrieben dass unexpected() aufgerufen wird wenn doch was geflogen kommt. Und unexpected() war es wiederum erlaubt selbst Exceptions zu werfen.
Ein Programm konnte sich also nicht darauf verlassen, dass aus einer throw() Funktion niemals was rausfliegt.Bei noexcept ist es dagegen garantiert. Wenn sich das Programm nicht daran hält, dann wird terminate() aufgerufen. Und terminate() darf eben keine Exceptions werfen.
Das ist so nicht ganz korrekt. std::unexpected darf zwar eine Exception werfen, diese wird aber nur aus der Funktion herausgereicht, wenn sie entweder eh auf die Spezifikation passt oder die Spezifikation std::bad_exception beinhaltet, in welchem Fall die geworfene Exception durch ein std::bad_exception-Objekt ersetzt wird. Andernfalls wird std::terminate aufgerufen. So oder so kommt nichts aus der Funktion, was nicht in der Exception-Spezifikation steht. (Vgl. 15.5.2 (2) in C++03)
-
Hm, das hatte ich dann falsch aufgeschnappt, sorry.
Macht natürlich mehr Sinn so.Nochwas: bei noexcept ist glaube ich vorgeschrieben dass kein Stack-Unwinding vor dem Aufruf von terminate() stattfindet. Auch ein Unterschied zu (und IMO eine Verbesserung gegenüber) throw(), wo Stack-Unwinding vorgeschrieben ist.
-
Ich fürchte, da habe ich ebenfalls schlechte Neuigkeiten:
C++11 15.5.1 (2) schrieb:
In such cases, std::terminate() is called (18.8.3). In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called. In the situation where the search for a handler (15.3) encounters the outermost block of a function with a noexcept-specification that does not allow the exception (15.4), it is implementation-defined whether the stack is unwound, unwound partially, or not unwound at all before std::terminate() is called. In all other situations, the stack shall not be unwound before std::terminate() is called. An implementation is not permitted to finish stack unwinding prematurely based on a determination that the unwind process will eventually cause a call to std::terminate().
-
Nexus schrieb:
Jay1980 schrieb:
Naja, bis ich da auf einem grünen Zweig bin, nehme ich assert-statements und exit mit Fehlercode - gibts halt jedesmal einen Abbruch, wenn irgendwo etwas schiefläuft.
assertist okay, um Logikfehler zu finden. Aber niemals für Laufzeitfehler. Und wiesoexit()?Mir geht es nur darum, dass ich ein zu Ende laufen des Programms verhindern will, wenn ich merke, dass die Daten im Programm fehlerhaft sind - da dachte ich, wie ziehe ich denn am besten den Stecker und mir kam exit() und assert() - je nachdem, wie ich gerade pruefen kann. Ich habe aber nur den Thread da gesehen, http://www.c-plusplus.net/forum/210888 und exit() scheint doch nicht so der Bringer zu sein, es wäre schon besser das Programm 'sanft' aber in jedem Fall zu beenden. Bei assert muss ich aufpassen, dass mir in der Release-Version nicht automatisch die Prüfung wegfällt, daher auch keine optimale Lösung, normalerweise sollten die assert-Statements da ja draußen oder entwertet sein, wenn ich das richtig verstanden habe.
Okay, mir scheint folgender Weg als geeignet: ich werfe einfach immer exceptions, aber lege dafür eben keine eigene Exception-Klasse an. Am Ende meines catch-Blocks beende ich das Programm in dem ich nach oben weiter werfen lasse, das heisst, das irgendwann terminate() kommt und ein sanftes Ende eintritt - soweit richtig?
Code poste ich dann, wenn ich damit etwas rumprobiert habe.
-
Kann ja nicht sein, das du jetzt keine eigenen Exception-Typen definieren kannst? Das ist wirklich ganz einfach. Mach das so: leite von einer speziellen Std-Exception ab und übergebe im Ctor deinen Fehlertext. Es macht keinen Sinn what() zu überschreiben.
class my_error : public std::exception { public: my_error(const std::string &err) : std::exception(err) {}; }; throw my_error("Da ist was schief gelaufen");Hier noch ein paar Infos:
http://msdn.microsoft.com/en-us/library/t65b74ad.aspx
-
@Jay1980: Du brauchst keine Exceptions nach oben werfen. Das tut C++ für dich automatisch, wenn du sie nicht fängst. Und ne Exception fangen und danach weiterwerfen ergibt selten bis gar nicht Sinn.
@Artchi: So sah ja auch mein Vorschlag aus.
-
Endlich hat es geklappt!
Danke fuer die Tipps insbesondere Archi.
Unten mal der kompilierende Code und da ich ja das Programm wirklich beenden will, muss ich doch weiterwerfen, sonst macht das Programm ja unterhalb des letzten catch-Blocks weiter - das will ich ja gerade nicht. Mir ist schon klar, dass man mit Exception-Handling die auftretenden Fehler wieder gerade zu biegen versucht, aber in meinem Fall will ich lieber einen Abbruch, daher meine Taktik mit dem 'Hochwerfen und auf terminate() vertrauen'.
// Error-Klasse class H2rError : public std::runtime_error { public: H2rError() : std::runtime_error( "H2rError-Fehlermeldung!"){} }; // Funktion bei der etwas anbrennen kann double Facade::computePairEntropyOfStrings(const std::string& stringToComputeOne, const std::string& stringToComputeTwo) { try { checkForSameStringLength(stringToComputeOne, stringToComputeTwo); // H2rError } catch( H2rError &e ){ std::cout << e.what() << std::endl; std::cerr << e.what() << std::endl; throw; // fuer Abbruch weiterwerfen } seqan::CharString columnStringOne(stringToComputeOne); seqan::CharString columnStringTwo(stringToComputeTwo); double res = getPairEntropyOfColumnStrings(columnStringOne, columnStringTwo); return res; } // Funktion die wirft void Facade::checkForSameStringLength(const std::string& stringToComputeOne, const std::string& stringToComputeTwo){ if ( stringToComputeOne.size() != stringToComputeTwo.size() ){ throw H2rError(); } }Okay, und die Zeichenkette im Konstruktor übergeben ist geschickter, das passe ich noch an.
-
Erstens sah meine Klasse genau so aus, bis auf dass ich struct verwendet habe und mir damit public erspart habe. Zweitens macht das, was du tust, keinen Sinn. Du gibst Fehlermeldungen aus und wirfst weiter. Das ist so, als würdest du es 2 mal sagen. Und dass du hier eine Exception werfen willst, lässt darauf schließen, dass die Ausgabe keinen Sinn ergibt. Mach den try-catch Block also Weg und arbeite ganz normal weiter nach dem Check.
-
Okay, ich denke langsam steige ich dahinter was du mit 'automatisch' meinst:
double Facade::computePairEntropyOfStrings(const std::string& stringToComputeOne, const std::string& stringToComputeTwo) { if ( stringToComputeOne.size() != stringToComputeTwo.size() ){ throw H2rError(); } /* try { checkForSameStringLength(stringToComputeOne, stringToComputeTwo); // H2rError } catch( H2rError &e ){ std::cerr << e.what() << std::endl; throw; // fuer Abbruch weiterwerfen } */ seqan::CharString columnStringOne(stringToComputeOne); seqan::CharString columnStringTwo(stringToComputeTwo); double res = getPairEntropyOfColumnStrings(columnStringOne, columnStringTwo); return res; }
-
Du kannst die check-Funktion ruhig weiterverwenden, wenn dir das besser gefällt. Ansonsten richtig.