|
|
|
@ -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 |
|
|
|
|