# HG changeset patch # User klao # Date 1107458682 0 # Node ID 5d8d64bde9c501b36f5ab8746a5374ae45fe0dee # Parent d3504fc075dc6a31e3083a1ef177fa82aac3f5b8 Latest LEMON exception and assert concepts diff -r d3504fc075dc -r 5d8d64bde9c5 src/work/klao/error.h --- a/src/work/klao/error.h Thu Feb 03 16:08:56 2005 +0000 +++ b/src/work/klao/error.h Thu Feb 03 19:24:42 2005 +0000 @@ -102,99 +102,112 @@ * Base class for exceptions used in LEMON. */ class Exception : public std::exception { - protected: - ///\e - const char *message; - public: ///\e - Exception() throw() : message(0) {} - ///\e - explicit Exception(const char *msg) throw() - : message(msg) {} + Exception() {} ///\e virtual ~Exception() throw() {} + + ///\e + virtual const char* exceptionName() const { + return "lemon::Exception"; + } ///\e virtual const char* what() const throw() { - if( message ) return message; - return "lemon::Exception"; + return exceptionName(); } }; - ///\e + /** + * \brief One of the two main subclasses of \ref Exception. + * + * Logic errors represent problems in the internal logic of a program; + * in theory, these are preventable, and even detectable before the + * program runs (e.g., violations of class invariants). + * + * For a typical example \see UninitializedParameterError. + */ class LogicError : public Exception { public: - ///\e - explicit LogicError() {} - ///\e - explicit LogicError(const char *s) - : Exception(s) {} + virtual const char* exceptionName() const { + return "lemon::LogicError"; + } }; - ///\e + + /** + * \brief One of the two main subclasses of \ref Exception. + * + * Runtime errors represent problems outside the scope of a program; + * they cannot be easily predicted and can generally only be caught as + * the program executes. + */ class RuntimeError : public Exception { public: - ///\e - explicit RuntimeError() {} - ///\e - explicit RuntimeError(const char *s) - : Exception(s) {} + virtual const char* exceptionName() const { + return "lemon::RuntimeError"; + } }; ///\e class RangeError : public RuntimeError { public: - ///\e - explicit RangeError(const char *s) - : RuntimeError(s) {} + virtual const char* exceptionName() const { + return "lemon::RangeError"; + } }; ///\e class IOError : public RuntimeError { public: - ///\e - explicit IOError(const char *s) - : RuntimeError(s) {} + virtual const char* exceptionName() const { + return "lemon::IOError"; + } }; ///\e class DataFormatError : public IOError { protected: - int line; - boost::shared_ptr file; + const char *_message; + int _line; + boost::shared_ptr _file; public: ///\e - explicit DataFormatError(const char *message) - : IOError(message), line(0) {} + explicit DataFormatError(const char *the_message) + : _message(the_message), _line(0) {} ///\e DataFormatError(const std::string &file_name, int line_num, - const char *message) - : IOError(message), line(line_num) { set_file(file_name); } + const char *the_message) + : _message(the_message), _line(line_num) { file(file_name); } ///\e - void set_line(int line_num) { line=line_num; } + void line(int line_num) { _line=line_num; } ///\e - void set_file(const std::string &file_name) { + void message(char *the_message) { _message=the_message; } + ///\e + void file(const std::string &file_name) { try { - file.reset(new std::string); - *file = file_name; + _file.reset(new std::string); + *_file = file_name; } catch(...) { - file.reset(); + _file.reset(); } } ///\e - int get_line() const { return line; } + int line() const { return _line; } + ///\e + const char* message() const { return _message; } /// \brief Returns the filename. /// /// Returns \e "(unknown)" if the filename was not specified. - const char* get_file() const { - if( file ) - return file->c_str(); + const char* file() const { + if( _file ) + return _file->c_str(); else return "(unknown)"; } @@ -204,18 +217,22 @@ const char *mes = 0; try { std::ostringstream ostr; - ostr << IOError::what(); - if( file || line ) { + ostr << _message; + if( _file || _line ) { ostr << " ("; - if( file ) ostr << "in file '" << *file << "'"; - if( file && line ) ostr << " "; - if( line ) ostr << "at line " << line; + if( _file ) ostr << "in file '" << *_file << "'"; + if( _file && _line ) ostr << " "; + if( _line ) ostr << "at line " << _line; ostr << ")"; } mes = ostr.str().c_str(); } catch(...) {} if( mes ) return mes; + return exceptionName(); + } + + virtual const char* exceptionName() const { return "lemon::DataFormatError"; } @@ -264,6 +281,10 @@ } catch(...) {} if( mes ) return mes; + return exceptionName(); + } + + virtual const char* exceptionName() const { return "lemon::AssertionFailedError"; } @@ -311,7 +332,11 @@ #endif #ifndef LEMON_ASSERT_HANDLER -# define LEMON_ASSERT_HANDLER ::lemon::assert_fail +# ifdef LEMON_ASSERT_EXCEPTION +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_throw +# else +# define LEMON_ASSERT_HANDLER ::lemon::assert_fail +# endif #endif #if defined(NDEBUG) || defined(LEMON_DISABLE_ASSERTS) @@ -323,6 +348,18 @@ /** * \brief Macro for assertions with customizable message * + * Macro for assertions with customizable message. + * + * The behaviour can be customized with LEMON_ASSERT_HANDLER, + * LEMON_ASSERT_EXCEPTION and LEMON_ASSERT_ABORT defines. Asserts can be + * disabled by defining either NDEBUG or LEMON_DISABLE_ASSERTS macros. + * + * \todo We should provide some way to reset to the default behaviour, + * shouldn't we? + * + * \todo This whole 'assert' business should be placed in a separate + * include file. + * * \todo __PRETTY_FUNCTION__ should be replaced by something * compiler-independant, like BOOST_CURRENT_FUNCTION */ @@ -333,7 +370,7 @@ __PRETTY_FUNCTION__, \ (msg), #exp, LEMON_ASSERT_ABORT), 0))) -# endif // NDEBUG +#endif // NDEBUG || LEMON_DISABLE_ASSERTS /** * \brief Macro for mark not yet implemented features. diff -r d3504fc075dc -r 5d8d64bde9c5 src/work/klao/error_test.cc --- a/src/work/klao/error_test.cc Thu Feb 03 16:08:56 2005 +0000 +++ b/src/work/klao/error_test.cc Thu Feb 03 19:24:42 2005 +0000 @@ -15,8 +15,8 @@ parse_line(); } catch(lemon::DataFormatError &e) { - e.set_file(fn); - e.set_line(5); + e.file(fn); + e.line(5); throw; } } @@ -27,26 +27,47 @@ try { parse_file("input.txt"); } + catch(lemon::Exception &e) { + cerr << "Exception '" << e.exceptionName() + << "' caught: " << endl; + cerr << e.what() << endl; + } catch(exception &e) { cerr << "Exception caught: " << endl; cerr << e.what() << endl; } try { + throw lemon::LogicError(); + } + catch(lemon::Exception &e) { + cerr << "Exception '" << e.exceptionName() + << "' caught: " << endl; + cerr << e.what() << endl; + } + + try { fail_assert(); } + catch(lemon::Exception &e) { + cerr << "Exception '" << e.exceptionName() + << "' caught: " << endl; + cerr << e.what() << endl; + } catch(exception &e) { cerr << "Exception caught: " << endl; cerr << e.what() << endl; } + cerr << endl; + // assert(1==0); LEMON_ASSERT(1==0, "Ellentmondas"); LEMON_FIXME("Nincs kesz"); } #undef LEMON_ASSERT_HANDLER -#define LEMON_ASSERT_HANDLER ::lemon::assert_fail_throw +#define LEMON_ASSERT_EXCEPTION #include