diff --git a/mrw/exception.hpp b/mrw/exception.hpp
index e1e073a..51ca78a 100644
--- a/mrw/exception.hpp
+++ b/mrw/exception.hpp
@@ -9,6 +9,10 @@
@license LGPL, see file COPYING
$Log$
+ Revision 1.5 2004/10/07 09:25:34 marc
+ new group for suggestions
+ new inheritance
+
Revision 1.4 2004/08/28 16:21:25 marc
mrw-c++-0.92 (mrw)
- new file: version.cpp
@@ -72,58 +76,6 @@ namespace mrw {
the bad exception and it is allowed to throw a new
exception. This is what my suggested exception handling concept
makes use of.
-
- @subsection excsug Suggested Exception Handling Rules
-
- -# derieve all your exceptions from mrw::exception
- -# write exception specifications as follows: @n
- (this specification is "binary", it only declares whether an exception
- is thrown or not, but it does not specify which exact exception can
- be thrown)
- - if no exception is thrown, specify @c throw(std::bad_exception)
- instead of @c throw() as you would normally specify
- - if any exception is thrown specify @c throw(std::exception) @n
- (@b Note: If you need a more specific declaration, you must also
- declare @c std::bad_exception in addition to your exceptions!)
- - only declare @c throw() if you are 100% sure, that it is absolutely
- impossible that this method ever throws an exception, that means
- this method calls no other function or method (not even from a
- system library) that does not declare @c throw()
- -# document the exact exception thrown with Doxygen's @c \@throw tag
- -# write an unexpected handler as follows
- (or link to a @ref AutoTrace "library"):
-
- @code
- void unexpectedHandler() {
- try {
- throw;
- } catch (mrw::exception& x) {
- // trace x.stacktrace() and x.what()
- } catch (std::exception& x) {
- // trace x.what()
- } catch (...) {
- // trace unknown unexpected
- }
- throw std::bad_exception(); // try to recover
- }
- @endcode
-
- What happens:
- - If you throw an exception in a method that declares not to
- throw an exception, the unexpected handler is called.
- - It writes a stack trace for you to be able to find your bug.
- - Then it throws a @c std::bad_exception, which is allowed to pass.
- - Your program does not abort, but continues running.
- - If higher in the stack you catch the exception, you may be
- able to recover.
- - If you throw an exception where you are allowed to, you only need to
- catch mrw::exception and you can access @c what() and @c stacktrace().
-
- For a proof of concept refer to
- @ref exceptionhandling.cpp "the example exceptionhandling.cpp".
-
- The unexpected handler is implemented ready to use in @ref
- AutoTrace "a separate library".
*/
//@{
@@ -162,6 +114,106 @@ call of fn0 successful
unexpected handler, the program would abort in function fn2 on
line 25. The output was produced by the following code:
*/
+
+ /** @defgroup exceptions Exceptions with Stack Trace
+
+ The following diagram shows the inheritance of the MRW exception
+ classes and how they are related to the C++ standard
+ exceptions. @c mrw::exception inherits @c std::exception, then a
+ inheritance corresponding to the standard is implemented below
+ @c mrw::exception. To prevent diamond-shaped inheritance, the MRW
+ exceptions below the @c mrw::exception base class do not inherit
+ from their corresponding standard exception.
+
+ The exception classes are meant as a replacement to the standard
+ exceptions that provide stack trace information. I suggest
+ exception handling according to @ref excsug.
+
+ @dot
+ digraph ExceptionInheritance {
+ graph [rankdir="LR"];
+ node [shape=record, fontname=Helvetica, fontsize=8];
+ edge [dir=back, headport=w, tailport=e, arrowtail=empty];
+
+ std_exception [label="std::exception"];
+ std_bad_alloc [label="std::bad_alloc"];
+ std_bad_cast [label="std::bad_cast"];
+ std_logic_error [label="std::logic_error"];
+ std_domain_error [label="std::domain_error"];
+ std_invalid_argument [label="std::invalid_argument"];
+ std_length_error [label="std::length_error"];
+ std_out_of_range [label="std::out_of_range"];
+ std_runtime_error [label="std::runtime_error"];
+ std_overflow_error [label="std::overflow_error"];
+ std_range_error [label="std::range_error"];
+ std_underflow_error [label="std::underflow_error"];
+ std_bad_exception [label="std::bad_exception"];
+ std_bad_typeid [label="std::bad_typeid"];
+
+ mrw_exception [label="mrw::exception" URL="\ref mrw::exception"];
+ mrw_bad_alloc [label="mrw::bad_alloc" URL="\ref mrw::bad_alloc"];
+ mrw_bad_cast [label="mrw::bad_cast" URL="\ref mrw::bad_cast"];
+ mrw_logic_error [label="mrw::logic_error" URL="\ref mrw::logic_error"];
+ mrw_domain_error [label="mrw::domain_error" URL="\ref mrw::domain_error"];
+ mrw_invalid_argument [label="mrw::invalid_argument" URL="\ref mrw::invalid_argument"];
+ mrw_length_error [label="mrw::length_error" URL="\ref mrw::length_error"];
+ mrw_out_of_range [label="mrw::out_of_range" URL="\ref mrw::out_of_range"];
+ mrw_runtime_error [label="mrw::runtime_error" URL="\ref mrw::runtime_error"];
+ mrw_overflow_error [label="mrw::overflow_error" URL="\ref mrw::overflow_error"];
+ mrw_range_error [label="mrw::range_error" URL="\ref mrw::range_error"];
+ mrw_underflow_error [label="mrw::underflow_error" URL="\ref mrw::underflow_error"];
+ mrw_bad_exception [label="mrw::bad_exception" URL="\ref mrw::bad_exception"];
+ mrw_bad_typeid [label="mrw::bad_typeid" URL="\ref mrw::bad_typeid"];
+
+ {rank=same; std_exception; mrw_exception;}
+ {rank=same; std_bad_alloc; mrw_bad_alloc;}
+ {rank=same; std_bad_cast; mrw_bad_cast;}
+ {rank=same; std_logic_error; mrw_logic_error;}
+ {rank=same; std_domain_error; mrw_domain_error;}
+ {rank=same; std_invalid_argument; mrw_invalid_argument;}
+ {rank=same; std_length_error; mrw_length_error;}
+ {rank=same; std_out_of_range; mrw_out_of_range;}
+ {rank=same; std_runtime_error; mrw_runtime_error;}
+ {rank=same; std_overflow_error; mrw_overflow_error;}
+ {rank=same; std_range_error; mrw_range_error;}
+ {rank=same; std_underflow_error; mrw_underflow_error;}
+ {rank=same; std_bad_exception; mrw_bad_exception;}
+ {rank=same; std_bad_typeid; mrw_bad_typeid;}
+
+ mrw_exception -> mrw_bad_alloc;
+ mrw_exception -> mrw_bad_cast;
+ mrw_exception -> mrw_logic_error;
+ mrw_logic_error -> mrw_domain_error;
+ mrw_logic_error -> mrw_invalid_argument;
+ mrw_logic_error -> mrw_length_error;
+ mrw_logic_error -> mrw_out_of_range;
+ mrw_exception -> mrw_runtime_error;
+ mrw_runtime_error -> mrw_overflow_error;
+ mrw_runtime_error -> mrw_range_error;
+ mrw_runtime_error -> mrw_underflow_error;
+ mrw_exception -> mrw_bad_exception;
+ mrw_exception -> mrw_bad_typeid;
+
+ std_exception -> std_bad_alloc;
+ std_exception -> std_bad_cast;
+ std_exception -> std_logic_error;
+ std_logic_error -> std_domain_error;
+ std_logic_error -> std_invalid_argument;
+ std_logic_error -> std_length_error;
+ std_logic_error -> std_out_of_range;
+ std_exception -> std_runtime_error;
+ std_runtime_error -> std_overflow_error;
+ std_runtime_error -> std_range_error;
+ std_runtime_error -> std_underflow_error;
+ std_exception -> std_bad_exception;
+ std_exception -> std_bad_typeid;
+
+ std_exception -> mrw_exception;
+
+ }
+ @enddot
+ */
+ //@{
/** @brief replacement for @c std::exception, that collects a stack trace
@pre #include
@@ -213,132 +265,191 @@ call of fn0 successful
};
/// Replacement for @c std::bad_alloc, but with stack trace
- class bad_alloc:
- virtual public mrw::exception, virtual public std::bad_alloc {
+ class bad_alloc: public mrw::exception {
public:
+ ~bad_alloc() throw() {}
virtual const char* what() const throw() {
- return std::bad_alloc::what();
+ return "mrw::bad_alloc";
}
};
/// Replacement for @c std::bad_cast, but with stack trace
- class bad_cast:
- virtual public mrw::exception, virtual public std::bad_cast {
+ class bad_cast: public mrw::exception {
public:
+ ~bad_cast() throw() {}
virtual const char* what() const throw() {
- return std::bad_cast::what();
+ return "mrw::bad_cast";
}
};
/// Replacement for @c std::bad_exception, but with stack trace
- class bad_exception:
- virtual public mrw::exception, virtual public std::bad_exception {
+ class bad_exception: public mrw::exception {
public:
+ ~bad_exception() throw() {}
virtual const char* what() const throw() {
- return std::bad_exception::what();
+ return "mrw::bad_exception";
}
};
/// Replacement for @c std::bad_typeid, but with stack trace
- class bad_typeid:
- virtual public mrw::exception, virtual public std::bad_typeid {
+ class bad_typeid: public mrw::exception {
public:
+ ~bad_typeid() throw() {}
virtual const char* what() const throw() {
- return std::bad_typeid::what();
+ return "mrw::bad_typeid";
}
};
/// Replacement for @c std::logic_error, but with stack trace
- class logic_error:
- virtual public mrw::exception, virtual public std::logic_error {
+ class logic_error: public mrw::exception {
public:
- logic_error(const std::string& arg): std::logic_error(arg) {}
+ ~logic_error() throw() {}
+ logic_error(const std::string& arg) throw(): _what(arg) {}
virtual const char* what() const throw() {
- return std::logic_error::what();
+ return _what.c_str();
}
+ private:
+ std::string _what;
};
/// Replacement for @c std::domain_error, but with stack trace
- class domain_error:
- virtual public mrw::exception, virtual public std::domain_error {
+ class domain_error: public mrw::logic_error {
public:
- domain_error(const std::string& arg): std::domain_error(arg) {}
+ ~domain_error() throw() {}
+ domain_error(const std::string& arg) throw(): mrw::logic_error(arg) {}
virtual const char* what() const throw() {
- return std::domain_error::what();
+ return mrw::logic_error::what();
}
};
/// Replacement for @c std::invalid_argument, but with stack trace
- class invalid_argument:
- virtual public mrw::exception, virtual public std::invalid_argument {
+ class invalid_argument: public mrw::logic_error {
public:
- invalid_argument(const std::string& arg): std::invalid_argument(arg) {}
+ ~invalid_argument() throw() {}
+ invalid_argument(const std::string& arg) throw(): mrw::logic_error(arg) {}
virtual const char* what() const throw() {
- return std::invalid_argument::what();
+ return mrw::logic_error::what();
}
};
/// Replacement for @c std::length_error, but with stack trace
- class length_error:
- virtual public mrw::exception, virtual public std::length_error {
+ class length_error: public mrw::logic_error {
public:
- length_error(const std::string& arg): std::length_error(arg) {}
+ ~length_error() throw() {}
+ length_error(const std::string& arg) throw(): mrw::logic_error(arg) {}
virtual const char* what() const throw() {
- return std::length_error::what();
+ return mrw::logic_error::what();
}
};
/// Replacement for @c std::out_of_range, but with stack trace
- class out_of_range:
- virtual public mrw::exception, virtual public std::out_of_range {
+ class out_of_range: public mrw::logic_error {
public:
- out_of_range(const std::string& arg): std::out_of_range(arg) {}
+ ~out_of_range() throw() {}
+ out_of_range(const std::string& arg) throw(): mrw::logic_error(arg) {}
virtual const char* what() const throw() {
- return std::out_of_range::what();
+ return mrw::logic_error::what();
}
};
/// Replacement for @c std::runtime_error, but with stack trace
- class runtime_error:
- virtual public mrw::exception, virtual public std::runtime_error {
+ class runtime_error: public mrw::exception {
public:
- runtime_error(const std::string& arg): std::runtime_error(arg) {}
+ ~runtime_error() throw() {}
+ runtime_error(const std::string& arg) throw(): _what(arg) {}
virtual const char* what() const throw() {
- return std::runtime_error::what();
+ return _what.c_str();
}
+ private:
+ std::string _what;
};
/// Replacement for @c std::overflow_error, but with stack trace
- class overflow_error:
- virtual public mrw::exception, virtual public std::overflow_error {
+ class overflow_error: public mrw::runtime_error {
public:
- overflow_error(const std::string& arg): std::overflow_error(arg) {}
+ ~overflow_error() throw() {}
+ overflow_error(const std::string& arg) throw(): mrw::runtime_error(arg) {}
virtual const char* what() const throw() {
- return std::overflow_error::what();
+ return mrw::runtime_error::what();
}
};
/// Replacement for @c std::range_error, but with stack trace
- class range_error:
- virtual public mrw::exception, virtual public std::range_error {
+ class range_error: public mrw::runtime_error {
public:
- range_error(const std::string& arg): std::range_error(arg) {}
+ ~range_error() throw() {}
+ range_error(const std::string& arg) throw(): mrw::runtime_error(arg) {}
virtual const char* what() const throw() {
- return std::range_error::what();
+ return mrw::runtime_error::what();
}
};
/// Replacement for @c std::underflow_error, but with stack trace
- class underflow_error:
- virtual public mrw::exception, virtual public std::underflow_error {
+ class underflow_error: public mrw::runtime_error {
public:
- underflow_error(const std::string& arg): std::underflow_error(arg) {}
+ ~underflow_error() throw() {}
+ underflow_error(const std::string& arg) throw(): mrw::runtime_error(arg) {}
virtual const char* what() const throw() {
- return std::underflow_error::what();
+ return mrw::runtime_error::what();
}
};
//@}
+
+ /** @defgroup excsug Suggested Exception Handling Rules
+
+ -# derieve all your exceptions from mrw::exception
+ -# write exception specifications as follows: @n
+ (this specification is "binary", it only declares whether an exception
+ is thrown or not, but it does not specify which exact exception can
+ be thrown)
+ - if no exception is thrown, specify @c throw(std::bad_exception)
+ instead of @c throw() as you would normally specify
+ - if any exception is thrown specify @c throw(std::exception) @n
+ (@b Note: If you need a more specific declaration, you must also
+ declare @c std::bad_exception in addition to your exceptions!)
+ - only declare @c throw() if you are 100% sure, that it is absolutely
+ impossible that this method ever throws an exception, that means
+ this method calls no other function or method (not even from a
+ system library) that does not declare @c throw()
+ -# document the exact exception thrown with Doxygen's @c \@throw tag
+ -# write an unexpected handler as follows
+ (or link to a @ref AutoTrace "library"):
+
+ @code
+ void unexpectedHandler() {
+ try {
+ throw;
+ } catch (mrw::exception& x) {
+ // trace x.stacktrace() and x.what()
+ } catch (std::exception& x) {
+ // trace x.what()
+ } catch (...) {
+ // trace unknown unexpected
+ }
+ throw std::bad_exception(); // try to recover
+ }
+ @endcode
+
+ What happens:
+ - If you throw an exception in a method that declares not to
+ throw an exception, the unexpected handler is called.
+ - It writes a stack trace for you to be able to find your bug.
+ - Then it throws a @c std::bad_exception, which is allowed to pass.
+ - Your program does not abort, but continues running.
+ - If higher in the stack you catch the exception, you may be
+ able to recover.
+ - If you throw an exception where you are allowed to, you only need to
+ catch mrw::exception and you can access @c what() and @c stacktrace().
+
+ For a proof of concept refer to
+ @ref exceptionhandling.cpp "the example exceptionhandling.cpp".
+
+ The unexpected handler is implemented ready to use in @ref
+ AutoTrace "a separate library".
+ */
+
+ //@}
}
#endif