ZMexception
(ZOOM exception class) object
as implemented by the ZOOM Exceptions package.
Note that all public C++ symbols used within this Exceptions package begin with the unlikely prefix "ZMex" (or, in the case of the preprocessor, "ZMEX") in order to help avoid namespace pollution. For example, we use "ZMexception" as the name of the class from which all other exception classes are (directly or indirectly) derived.
Additionally, all ZOOM-generated
ZMexception
classes
will use at least "ZMx" as their name prefix.
More typically, to avoid internal name clashes,
the names start with a short string identifying the package,
e.g. "ZMxHep" for HepTuple,
or "ZMxpv" for the PhysicsVectors package.
It is recommended that users defining their own
ZMexception
s
establish and employ some similar convention.
// Required header, with recommended code guard: #ifndef ZMEXCEPTION_H #include "Exceptions/ZMexception.h" #endif // ZMEXCEPTION_H // Required (sample) declaration (for use in a .h file): ZMexStandardDefinition( ZMexception, ZMxOops ); // Defines class ZMxOops : public ZMexception { ... }; // Required (sample) definition (for use in a .cc file): ZMexClassInfo ZMxOops::_classInfo( "Oops", "ExcTest", ZMexWARNING ); // Provides certain details specific to the new classIn the example above:
ZMxOops
ZMexception
ZMxOops
.
ZMexception
may be used as the parent.
"Oops"
"ExcTest"
ZMexWARNING
ZMxOops
.
ZMxOops::setName("Whoops");
ZMxOops::setFacility("Other");
ZMxOops::setSeverity(ZMexERROR);
ZM_USE_NAMESPACES
defined.
If the ZMexceptions package is built with this defined, all global symbols
will be placed in the namespace zmex.
This means that user code linking with the namespace-enambled version must properly qualify symbols used. The code may do this overall by declaring
using namespace zmex;or by individually qualifying each symbol needed from the Exceptions package:
ZMexStandardDefinition( zmex::ZMexception, Whoops ); zmex::ZMexClassInfo Whoops::_classInfo( "Whoops", "MyCode", ZMexERROR );Two items of note here:
ZMexStandardDefinition
, being a macro,
is not in the zmex namespace.
When ZMthrow-ing ZMexceptions, note that ZMthrow and ZMthrow_from are macros, so they still appear as if in the global namespace:
ZMthrow (Whoops("A goof"));
It is possible to write code that will work whether or not namespaces are enabled. ZMenvironment.h provides two useful macros:
ZM_USING_NAMESPACE (zmex);
would become either nothing or
using namespace zmex;
ZM_QUAL_NAME (zmex, ZMexception)
would become either
ZMexception
or zmex::ZMexception
.
ZMthrow()
,
to make use of ZMexception
and its descendent classes.
Before using this capability,
insert the following line to provide the necessary declaration:
#include "Exceptions/ZMthrow.h"
Thereafter, an exception of a class defined as shown above is typically constructed and thrown within a single statement, such as:
ZMthrow( ZMxOops("Ouch!") );
Here, "Ouch!" may be arbitrary text to be associated with this particular occurrence (exception instance). The text will be logged, as described below. A second macro is provided for cases where it is preferable to supply some other line and file as the actual origin of the throw:
ZMthrow_from( exception, line, file );
ZMException
class provides a constructor
taking an ostringstream
.
And the ZMexStandardDefinition
macro which helps create derived exceptions
also provides this constructor.
For example, you can do:
std::ostringstream oss; oss << "Ouch: " << n << " errors too many"; ZMthrow( ZMxOops(oss) );
ExcTest
program has been compiled
with appropriate compiler switches that enable use of C++ exceptions,
the logged message resulting from the above
ZMthrow(...)
example will be:
ExcTest-S-Oops [#1] Ouch! Wed Mar 4 17:18:55 1998 -- ZMthrow was issued at line 25 of file "/disk4/home/me/testarea/exctest1.cc" ... Exception thrown!The parts of this message are interpreted as follows:
ExcTest
ExcTest
facility;
-S-
ZMexSEVERE
-- see below);
Oops
[#1]
Ouch!
Wed Mar 4 17:18:55 1998
of file "..."
-- ZMthrow was issued at line 25
... Exception thrown!
ZMthrow_from
instead of
ZMthrow
as illustrated here:
{ // in usual code
throw_foo (5, __FILE__, __LINE__); // because I found a foo error
... }
// and an error message preparation routine
void throw_foo ( int n, std::string file, int line )
{ s=make_message(n) // prepare foo error message s based on the 5
ZMthrow_from (Exc_Foo (s), file, line); }
ZMexNORMAL
ZMexINFO
ZMexWARNING
ZMexERROR
ZMexSEVERE
ZMexFATAL
ZMexPROBLEM
ZMthrow
'n exception.
A handler is responsible
for having the exception instance logged, for taking any remedial
action appropriate to the exception instance, and for determining
whether the exception instance can safely be ignored by the user code.
The Exceptions package includes
a pre-defined handler class,
ZMexHandler
.
Instances of this class can be configured
with any of a number of pre-defined handler behaviors
(listed below).
Each exception class is associated with a handler to be applied to all
ZMthrow
'n instances of that class.
By default, this handler implements
the behavior known as ZMexHandleViaParent()
;
this applies the behavior -- whatever it may be --
of the parent exception class' handler to the current exception class.
A user may change this behavior in either of two ways. A different handler may be associated with an exception class when the class is defined:
ZMexClassInfo ZMxOops::_classInfo( "Oops", "ExcTest", ZMexWARNING, ZMexHandler( ZMexIgnoreAlways() ) );Alternatively, the handler associated with an exception class may be changed dynamically:
#include "Exceptions/ZMexHandler.h" // ... ZMexOops::setHandler( ZMexHandler( ZMexIgnoreAlways() ) );
The given behavior will apply to any exceptions ZMthrow
'n after the
handler has been established.
ZMexThrowAlways()
ZMthrow
'n exception instance
will, after handling, become the object of a C++
throw
.
ZMexIgnoreAlways()
ZMthrow
'n exception instance
will be handled, but will have no further affect on subsequent control flow.
ZMexThrowErrors()
ZMthrow
'n exception instance
will, after handling, be thrown if its severity is
ZMexERROR
or higher,
but will be ignored if of a lesser severity.
Note: this is the
default handling behavior
of the package's ZMexception
class,
the intended (direct or indirect) ancestor class
of all other exception classes.
ZMexIgnoreNextN( n )
ZMthrow
'n instance of this class
will be ignored after handling;
subsequent instances will be thrown after handling.
ZMexHandleViaParent()
ZMthrow
'n exception instance
will be handled by the handler
that is currently associated with the parent exception class.
ZMthrow
'n
exception.
A logger is responsible only for routing the message
associated with an exception instance; it is not responsible for
determining or formatting any message.
The Exceptions package includes
a pre-defined logger class,
ZMexLogger
.
Instances of this class can be configured
with any of a number of pre-defined logger behaviors
(listed below).
Each exception class is associated with a logger to be applied to all
ZMthrow
'n instances of that class.
By default, this logger implements
the behavior known as ZMexLogViaParent()
;
this applies the behavior -- whatever it may be --
of the parent exception class' logger to the current exception class.
A user may change this behavior in either of two ways. A different logger may be associated with an exception class when the class is defined:
ZMexClassInfo ZMxOops::_classInfo( "Oops", "ExcTest", ZMexWARNING, ZMexHandler( ZMexIgnoreAlways() ), ZMexLogger( ZMexLogAlways() ) );Alternatively, the logger associated with an exception class may be changed dynamically:
#include "Exceptions/ZMexLogger.h" // ... ZMexOops::setLogger( ZMexLogger( ZMexLogAlways() ) );The given behavior will apply to any exceptions
ZMthrow
'n after the
logger has been established, provided the handler invokes the logger.
ZMexLogAlways( ostream Dest )
ZMthrow
'n exception instances
processed by a logger with this behavior
will appear in the designated destination.
Note:
this is the default logging behavior
of the package's ZMexception
class,
the intended (direct or indirect) ancestor class
of all other exception classes.
ZMthrow
'n,
will refrain from logging and simply throw
(in the C++ sense).
We will name this class ZMxCppStyle
(code adapted from "Exceptions/test/exctest4.cc"):
#ifndef ZMEXCEPTION_H #include "Exceptions/ZMexception.h" #endif // ZMEXCEPTION_H // Declaration: ZMexStandardDefinition( ZMexception, ZMxCppStyle ); // Definition: ZMexClassInfo ZMxCppStyle::_classInfo( "CppStyle", "ExcTest", ZMexERROR , ZMexHandler( ZMexThrowAlways() ) , ZMexLogger ( ZMexLogNever() ) );
ZMexERROR
and above that have
been ZMthrow
'n.
Known as ZMerrno
,
this capability is in addition to the logging described earlier,
and allows user code to interrogate and make decisions
based on such exceptions.
To use this ZMerrno
facility,
insert the following line to provide the necessary declaration:
#include "Exceptions/ZMerrno.h"This declaration makes the following operations (functions) available:
ZMerrno.setMax( unsigned int limit = 100 )
ZMthrow
'n exceptions to be recorded.
ZMthrow
'n
exception will cause the oldest (least recent) recorded exception
to be forgotten
(i.e., discarded from ZMerrno
's list).
ZMerrno
facility
is effectively disabled,
and any recorded exceptions are immediately permanently discarded.
ZMerrno.write( const ZMexception & exc )
ZMerrno.count()
ZMthrow
'n exceptions ever recorded
via ZMerrno.write()
,
whether or not they are still recorded.
ZMthrow
'n exceptions
currently recorded.
ZMerrno.clear()
ZMthrow
'n exceptions
that have occurred during any arbitrary time interval.
ZMerrno.countSinceCleared()
ZMthrow
'n exceptions
that have been recorded via
ZMerrno.write()
,
whether or not they are still recorded,
since the user counter was last cleared (see previous function).
ZMerrno.name( unsigned int k = 0 )
ZMerrno
.
ZMerrno.name()
gives the (string) name of the latest recorded exception,
while ZMerrno.name(1)
gives the name of the exception
recorded immediately before the last one.
ZMerrno.get( unsigned int k = 0 )
ZMerrno
.
Thus, ZMerrno.get()
gives a (const pointer to) the latest recorded exception,
while ZMerrno.get(1)
gives the corresponding pointer to the exception
recorded immediately before the last one.
ZMthrow
'n, etc.
ZMerrno
does not go back as far as requested.
ZMerrno.erase()
erase()
'd
so as not to wipe out history
for other, more interesting, exceptions.