new group for suggestions
new inheritance
This commit is contained in:
@@ -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
|
||||
|
Reference in New Issue
Block a user