#include <x/exception.H> try { // ... if (!parse_file(filename)) { throw EXCEPTION("File parsing error: " << filename); } // ... if (rmdir("data") < 0) { throw SYSEXCEPTION("rmdir(\"data\") failed: "); } // ... } catch (const x::sysexception &e) { LOG_ERROR(e); LOG_TRACE(e->backtrace); } catch (const x::exception &e) { std::cerr << e.what(); } // ... std::cerr << e << std::endl;
This library throws
x::exception
exceptions, but applications should use the
EXCEPTION
or a
SYSEXCEPTION
macro.
These macros take an argument that can generally appear on the right
hand side of a “std::ostream <<”. The exception text
gets formatted using an output stream formatter.
x::exception
can be passed
to a std::ostream
via the
<<
operator.
It is also a subclass of std::exception
that
implements what
() by returning a pointer to a
C string that includes both the error message text and the backtrace.
Alternatively, x::exception
s can also
get also logged by
the logging macros.
Internally, it's a reference-counted object,
with a
backtrace
member that
describes the stack backtrace at the time the exception object was
constructed (which is usually just before it gets thrown).
The application must be compiled with g++'s
-fno-omit-frame-pointer
option, and linked with
-export-dynamic
.
The absence of -fno-omit-frame-pointer
may result in
thrown exceptions causing a segfault, with some versions of
g++, and
without -export-dynamic
backtrace
() can't resolve
symbols from the ELF objects that were linked
directly into the executable.
SYSEXCEPTION
constructs a
x::sysexception
,
a subclass of x::exception
. This macro appends
the system error message text, based on the value of
errno
to the error message that's passed as an argument
to the macro. The value of errno
is also saved, and
may be retrieved by the getErrorCode
() method.
class custom_exception { public: int errcode; custom_exception(int n) : errcode(n) { } }; // ... try { throw CUSTOM_EXCEPTION(custom_exception, 100); } catch (const x::custom_exception<custom_exception> &c) { doSomething(c->errcode); // ... }
The
CUSTOM_EXCEPTION
macro
constructs a temporary class that multiply derives from
x::custom_exception<argument>
, with
argument
given as the first macro parameter, and
x:;exception
.
The remaining macro parameters get forwarded to its constructor.
The temporary class is a subclass of
x::exception
, and it's catchable by
a const x::exception &
, but passing it
to a std::ostream
via the
<<
operator results in a single string,
the name of the custom subclass.
Dereferencing
x::custom_exception<argument>
,
produces an instance argument
, instantiated
using the arguments to the CUSTOM_EXCEPTION
.
class custom_exception { public: int errcode; custom_exception(int n) : errcode(n) { } void describe(x::exception &e) { e << "Internal error " << errcode; } };
Use a describe
() method, that takes a
native reference to
x::exception
, to provide a generic error
message text, that gets written
to a std::ostream
by this
x::exception
, instead of just a class name.
describe
() gets invoked to provide the
exception's description just after its constructor gets invoked, and
before the actual exception gets thrown.
class custom_exception { public: int errcode; class base { public: static void base_function(); }; custom_exception(int n) : errcode(n) { } }; typedef x::custom_exception<custom_exception> custom_thrown_exception; // ... try { throw CUSTOM_EXCEPTION(custom_exception, 100); } catch (const custom_thrown_exception &c) { custom_thrown_exception::base::base_function(c->errcode); }
If a custom exception class defines an inner class named
“base”, the
x::custom_exception
template contains
a member typedef alias for this class.
Although a
x::custom_exception
is not an
x::ref
(it subclasses it), this allows code
to treat it similarly, with a defined base class.