Fehler markieren; Exceptions, return-Codes oder Error-Attribut?
-
Ich bin nach deiner Liste etwas überrascht, dass du zu b und c tendierst, hatte ich doch beim Durchlesen selber erwartet, dass gleich die Frage kommt, warum man manchmal keine Exceptions benutzt. Wo siehst du denn die Vorteile der anderen, außer dass du dir damit mit viel Aufwand so etwas wie Exceptions basteln kannst?
-
Okay, C++-Exceptions habe ich nur kurz überflogen in diversen Büchern und da scheint es viel zu beachten zu geben. Ich habe aber nun ein Beispiel gefunden, was ich versucht habe auf meinen Fall anzupassen, mal schauen ob ich das richtig verstanden habe und ob ich damit vermutlich keine unangenehmen Überraschungen erleben werde.
Ich habe etwas Bammel gehabt, dass mir ja der Programmfluss mit einer Exception abhaut, dazu die zusätzliche Komplexität. Ebenso steht im Google-C++-Guide, dass die komplett auf Exceptions in deren Projekten verzichten, daher dachte ich, dass ich das auch so machen sollte. Aber naja, nachdem ich nun etwas nachgelesen habe, denke ich versuche ich mich mal kurz an Exceptions, in Java klappte das ja auch, wenn mir da IDE und Sprache auch einiges abgenommen hat.
Also los gehts mit Exceptions und C++ für mich:
// 1. Die Funktion wo es vielleicht kracht ... double Facade::computePairEntropyOfStrings(const std::string& stringToComputeOne, const std::string& stringToComputeTwo) { try { checkForSameStringLength(stringToComputeOne, stringToComputeTwo); } catch( H2rException &e ){ std::cout << e.what() << std::endl; std::cerr << e.what() << std::endl; } catch(...) { throw; // schmeiss hoch } seqan::CharString columnStringOne(stringToComputeOne); seqan::CharString columnStringTwo(stringToComputeTwo); double res = getPairEntropyOfColumnStrings(columnStringOne, columnStringTwo); return res; } // 2. Die Funktion die als Werfer markiert ist ... void Facade::checkForSameStringLength(const std::string& stringToComputeOne, const std::string& stringToComputeTwo){ if ( stringToComputeOne.size() != stringToComputeTwo.size() ){ throw H2rException; } } // 3. Meine Exception-Klasse // aus Schneeweiss S. 161f class H2rException : public std::exception { public: H2rException(char *where) : txt(where) {} const char* what() const throw(); private: char *txt; }; const char* H2rException::what() const throw() { static std::string s; s = "H2rException ist in "; s += txt; s += " aufgetreten."; return s.c_str(); }... okay, mal schauen ob das klappt, aber es sollte nichts schiefgehen, da
- wenn meine Exception erkannt wird, dann wird etwas Text ausgegeben und weiter nach oben geworfen, also terminate ausgeführt.
- wenn eine andere Exception erkannt wird, dann wird durch die Ellipse auch terminate() aufgerufen, ich brauche mir also keine Sorgen machen, dass eine Exception auftritt, die unentdeckt bleibt. Habe ich das richtig verstanden?
-
Ich habe gerade keine Zeit, deinen Code durchzulesen, aber guck dir doch dies mal an:
http://magazin.c-plusplus.net/artikel/Exception-Handling
http://www.c-plusplus.net/forum/219864
http://www.c-plusplus.net/forum/219865
-
Du kannst in deinem Code vieles vereinfachen. Zuallererst, dass du nicht alles mit catch(...) fangen musst. Was du nicht fängst, wird automatisch wetergeworfen.

Deine Exception-Klasse solltest du von einer der von std::exception abgeleiteten Klassen ableiten. Da gibt es z.B. length_error. Also könntest du deine Klasse wie folgt definieren:
// Error ist viel sexier als Exception struct H2rError : std::length_error { H2rError(const std::string& msg) std::length_error(msg) {} };
-
Ok, danke für den Tipp ... bis jetzt kompiliert mein Beispiel noch nicht sefix!
Falls einer eine kompilierbare EigeneErrorKlasse parat hat, danke. Irgendwas passt da nicht, nichts kompiliert bei mir ich habe auch schon diverse Beipiele abgetippt und im Netz geschaut, etwa http://www.rpg-studio.de/scientia/C%2B%2B/Tutorial:_16._Fehlerbehandlung#Eigene_ExceptionklassenKomisch, mir fiel auch auf, dass da teilweise unterschiedliche Header eingebunden werden in den Beispielen, daher die Bitte nach einem kompilierbaren Beispiel.
-
Du musst <stdexcept> statt <exception> inkludieren.
-
Hilft mir nichts, brauch ein ganzes Minibeispiel, ich habe nun schon 5 Stück abgetippt, immer ist es irgendwas anderes.
-
Du könntest ja mal die Fehlermeldungen zeigen.
-
#ifndef H2RERROR_H #define H2RERROR_H #include <string> #include <iostream> #include <exception> class H2rError : public std::exception { public: virtual char const* what() throw(); }; char const* H2rError::what() throw(){ return "My Error Message"; } #endif /* H2RERROR_H */Fehlermeldung:
h2rerror.h: In member function ‘virtual const char* H2rError::what()’:
In file included from facade.h:16,
from main.h:9,
from main.cpp:4:
h2rerror.h:11: error: expected primary-expression before ‘,’ token
h2rerror.h: At global scope:
h2rerror.h:14: error: redefinition of ‘const char* H2rError::what()’
h2rerror.h:11: error: ‘virtual const char* H2rError::what()’ previously defined here
h2rerror.h:14: error: expected unqualified-id before ‘{’ tokenDas Beispiel kommt von hier http://www.rpg-studio.de/scientia/C%2B%2B/Tutorial:_16._Fehlerbehandlung#Eigene_Exceptionklassen und wenn ich das Beispiel via Copy und Paste in ein neues Projekt stelle, dann klappt das auch - jemand eine Idee?
-
Wieso zum Himmel überschreibst du what()? Finger davon!
-
Jay1980 schrieb:
const char* H2rException::what() const throw() { static std::string s; s = "H2rException ist in "; s += txt; s += " aufgetreten."; return s.c_str(); }
static std::string s;?
Wirklich?
-
Bezogen auf den zuletzt von Jay1980 geposteten Code:
Konkret fallen mir zwei Dinge auf: Erstens ist what() throw() nicht genug; die von std::exception verwendete Signatur ist
virtual char const *what() const throw();Zweitens gehört die Definition der Methode nicht in den Header, sondern in eine eigene Übersetzungseinheit, sonst kriegst du damit später Linkerfehler. Beides wird deinen Compilerfehler aber nicht auslösen, sondern würde dir erst später Probleme verursachen. Die Fehlermeldung
h2rerror.h:11: error: expected primary-expression before ‘,’ token
gekoppelt mit der völligen Abwesenheit von Kommata in deinem Code macht mich ziemlich sicher, dass sich da ein Tippfehler eingeschlichen hat, den du nicht mit herauskopiert hast.
-
Und von Exception-Spezifikationen lass lieber auch die Finger. Es gibt einen Grund, warum die seit neuestem deprecated sind.
Und vor Internettutorials hat man dich doch hier bestimmt auch schon gewarnt.
-
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. Das mit dem Error-Handling scheint mir echt mühsam und tricky zu sein, gerade wenn da wohl erst vor einiger Zeit Ansätze als deprecated eingestuft wurden.
@SeppJ das heisst ich sollte nur die Exceptions der STL nutzen und keine 'eigenen' bauen sollen?
-
Jay1980 schrieb:
Das mit dem Error-Handling scheint mir echt mühsam und tricky zu sein, gerade wenn da wohl erst vor einiger Zeit Ansätze als deprecated eingestuft wurden.
Naja, die Community weiss eigentlich seit vielen Jahren dass die Exception-Specs in C++ nicht wirklich sinn machen.
Da C++11 das erste echte Update für C++ ist (C++03 war bloss ne Revision des 98er Standards), konnten sie natürlich auch erst jetzt deprecated gemacht werden.
-
Nur kann man sie in diesem Fall ja nicht wirklich weglassen, weil std::exception::what() nun mal const throw() ist (bzw. const noexcept in C++11, aber throw() ist da ja ein Alias für noexcept).
Es ist ja auch so, dass die Kritik an Exception-Spezifikationen sich vor allem gegen solche richtet, die nur bestimmte Exceptions erlauben. Die Garantie zu geben, dass überhaupt keine Exception geworfen werden kann, ist auch im neuen Standard nicht veraltet, und ob jetzt throw() oder noexcept da steht, ist erst mal von mäßiger Wichtigkeit.
-
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.
-
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()?
-
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.