Hi all,
I'm currently trying to come up with a decent exception base class for
some modules of ours and was thinking about adding exception-chaining
(yes, like in Java :-)
The following points where important for me:
* Must inherit from std::exception
* Should allow for a std::exception to be the start of the exception
chain.
* throw by value / catch by const reference
As exception chaining seems to be rather obscure with C++, I'm
interested what other think about the solution (find code below).
thanks,
br,
Martin
--CODE--
[**** Usage would then roughly be like this ***]
using namespace std;
using namespace my_project_ns;
void f3e() {
throw std::runtime_error("Any std::exception will do ...");
}
void f2e() {
try {
f3e();
}
catch(std_exc_catch_t e) {
throw chained_exception("My exc", &e);
}
}
void f1() {
try {
f2e();
} catch(ch_exc_catch_t ce) {
print_exc_chain(ce); // or do something else with the exception
}
}
int main(int argc, char* argv)
{
f1();
return 0;
}
--CODE--
[**** header ****]
namespace my_project_ns {
////////////////////////////////////////////////////////////
class chained_exception : virtual public std::exception
{
private:
// No copy operator is needed.
chained_exception& operator=(const chained_exception&);
public:
chained_exception(const chained_exception&);
chained_exception();
chained_exception(const std::string&);
typedef const std::exception* exc_ref_t;
chained_exception(const exc_ref_t exc_cause);
chained_exception(const std::string& msg, exc_ref_t exc_cause);
virtual chained_exception* clone() const;
virtual ~chained_exception();
virtual const char *what() const;
bool has_cause() const;
const chained_exception *const chained_cause() const;
const char *cause_typename() const;
const char *cause_what() const;
private:
typedef const chained_exception* chn_exc_ref_t;
const std::string m_msg;
const std::string m_cause_typename;
const std::string m_cause_msg;
chn_exc_ref_t m_cause;
};
////////////////////////////////////////////////////////////
typedef const std::exception& std_exc_catch_t;
typedef const chained_exception& ch_exc_catch_t;
////////////////////////////////////////////////////////////
void print_exc_chain(ch_exc_catch_t ce);
}; // namespace my_project_ns
[**** implementation ****]
#include "chained_exception.h"
namespace my_project_ns {
using namespace std;
////////////////////////////////////////////////////////////
chained_exception::chained_exception(const chained_exception& other)
: exception(other),
m_msg(other.m_msg),
m_cause_typename(other.m_cause_typename),
m_cause_msg(other.m_cause_msg),
m_cause(NULL)
{
if(other.m_cause)
m_cause = other.m_cause->clone();
}
////////////////////////////////////////////////////////////
chained_exception::chained_exception()
: exception(),
m_msg(),
m_cause_typename(),
m_cause_msg(),
m_cause(NULL)
{
}
////////////////////////////////////////////////////////////
chained_exception::chained_exception(const string& msg)
: exception(),
m_msg(msg),
m_cause_typename(),
m_cause_msg(),
m_cause(NULL)
{
}
////////////////////////////////////////////////////////////
chained_exception::chained_exception(exc_ref_t exc_cause)
: exception(),
m_msg(),
m_cause_typename(typeid(*exc_cause).name()),
m_cause_msg(exc_cause->what()),
m_cause(NULL)
{
chn_exc_ref_t p = dynamic_cast<chn_exc_ref_t>(exc_cause);
if(p)
m_cause = p->clone();
}
////////////////////////////////////////////////////////////
chained_exception::chained_exception(const string& msg, exc_ref_t
exc_cause)
: exception(),
m_msg(msg),
m_cause_typename(typeid(*exc_cause).name()),
m_cause_msg(exc_cause->what()),
m_cause(NULL)
{
chn_exc_ref_t p = dynamic_cast<chn_exc_ref_t>(exc_cause);
if(p)
m_cause = p->clone();
}
////////////////////////////////////////////////////////////
// virtual
chained_exception* chained_exception::clone() const
{
return new chained_exception(*this);
}
////////////////////////////////////////////////////////////
// virtual
chained_exception::~chained_exception()
{
if(m_cause)
delete m_cause;
m_cause = NULL;
}
////////////////////////////////////////////////////////////
bool chained_exception::has_cause() const
{
return !m_cause_typename.empty();
}
////////////////////////////////////////////////////////////
const chained_exception *const chained_exception::chained_cause() const
{
return m_cause;
}
////////////////////////////////////////////////////////////
const char *chained_exception::cause_typename() const
{
return m_cause_typename.c_str();
}
////////////////////////////////////////////////////////////
const char *chained_exception::cause_what() const
{
return m_cause_msg.c_str();
}
////////////////////////////////////////////////////////////
const char *chained_exception::what() const
{
return m_msg.c_str();
}
////////////////////////////////////////////////////////////
void print_exc_chain(ch_exc_catch_t ce) {
cout << "* Exception * "
<< typeid(ce).name()
<< ": "
<< ce.what()
<< "\n";
std::string indent(" ");
for(const chained_exception* next=&ce; next; next =
next->chained_cause()) {
if(next->has_cause()) {
cout << "* caused by * "
<< indent.c_str()
<< next->cause_typename()
<< ": "
<< next->cause_what()
<< "\n";
}
indent.push_back(' ');
}
}
}; // namespace my_project_ns
--
[ See http://www.gotw.ca/resources/clcm.htm
for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


|