new group for suggestions

new inheritance
master
Marc Wäckerlin 20 years ago
parent ed4c5d2cb5
commit 40beb53a91
  1. 311
      mrw/exception.hpp

@ -9,6 +9,10 @@
@license LGPL, see file <a href="license.html">COPYING</a> @license LGPL, see file <a href="license.html">COPYING</a>
$Log$ $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 Revision 1.4 2004/08/28 16:21:25 marc
mrw-c++-0.92 (mrw) mrw-c++-0.92 (mrw)
- new file: version.cpp - new file: version.cpp
@ -72,58 +76,6 @@ namespace mrw {
the bad exception and it is allowed to throw a new the bad exception and it is allowed to throw a new
exception. This is what my suggested exception handling concept exception. This is what my suggested exception handling concept
makes use of. 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 unexpected handler, the program would abort in function fn2 on
line 25. The output was produced by the following code: 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 /** @brief replacement for @c std::exception, that collects a stack trace
@pre #include <mrw/exception.hpp> @pre #include <mrw/exception.hpp>
@ -213,132 +265,191 @@ call of fn0 successful
}; };
/// Replacement for @c std::bad_alloc, but with stack trace /// Replacement for @c std::bad_alloc, but with stack trace
class bad_alloc: class bad_alloc: public mrw::exception {
virtual public mrw::exception, virtual public std::bad_alloc {
public: public:
~bad_alloc() throw() {}
virtual const char* what() const 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 /// Replacement for @c std::bad_cast, but with stack trace
class bad_cast: class bad_cast: public mrw::exception {
virtual public mrw::exception, virtual public std::bad_cast {
public: public:
~bad_cast() throw() {}
virtual const char* what() const 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 /// Replacement for @c std::bad_exception, but with stack trace
class bad_exception: class bad_exception: public mrw::exception {
virtual public mrw::exception, virtual public std::bad_exception {
public: public:
~bad_exception() throw() {}
virtual const char* what() const 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 /// Replacement for @c std::bad_typeid, but with stack trace
class bad_typeid: class bad_typeid: public mrw::exception {
virtual public mrw::exception, virtual public std::bad_typeid {
public: public:
~bad_typeid() throw() {}
virtual const char* what() const 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 /// Replacement for @c std::logic_error, but with stack trace
class logic_error: class logic_error: public mrw::exception {
virtual public mrw::exception, virtual public std::logic_error {
public: 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() { 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 /// Replacement for @c std::domain_error, but with stack trace
class domain_error: class domain_error: public mrw::logic_error {
virtual public mrw::exception, virtual public std::domain_error {
public: 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() { 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 /// Replacement for @c std::invalid_argument, but with stack trace
class invalid_argument: class invalid_argument: public mrw::logic_error {
virtual public mrw::exception, virtual public std::invalid_argument {
public: 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() { 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 /// Replacement for @c std::length_error, but with stack trace
class length_error: class length_error: public mrw::logic_error {
virtual public mrw::exception, virtual public std::length_error {
public: 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() { 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 /// Replacement for @c std::out_of_range, but with stack trace
class out_of_range: class out_of_range: public mrw::logic_error {
virtual public mrw::exception, virtual public std::out_of_range {
public: 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() { 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 /// Replacement for @c std::runtime_error, but with stack trace
class runtime_error: class runtime_error: public mrw::exception {
virtual public mrw::exception, virtual public std::runtime_error {
public: 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() { 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 /// Replacement for @c std::overflow_error, but with stack trace
class overflow_error: class overflow_error: public mrw::runtime_error {
virtual public mrw::exception, virtual public std::overflow_error {
public: 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() { 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 /// Replacement for @c std::range_error, but with stack trace
class range_error: class range_error: public mrw::runtime_error {
virtual public mrw::exception, virtual public std::range_error {
public: 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() { 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 /// Replacement for @c std::underflow_error, but with stack trace
class underflow_error: class underflow_error: public mrw::runtime_error {
virtual public mrw::exception, virtual public std::underflow_error {
public: 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() { 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 #endif

Loading…
Cancel
Save