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>
$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 <mrw/exception.hpp>
@ -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

Loading…
Cancel
Save