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>
|
@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
|
||||||
|
Reference in New Issue
Block a user