Exception Handling
Contents
Exception Handling
Exceptions handling is the most difficult part for any well-developed software. Because of the diversity of exceptions, HIPP is not designed to automatically solve them. Instead, HIPP provides an Unified Exception Model which reports exceptions to users, and leave users freedom to handling it.
HIPP’s exception system is designed by the standard way in modern C++. HIPP provides
layers of exceptions classes, which are all derived from the root exception class std::exception.
One special thing is that
each exception class in HIPP has two super classes, one describes the application which
leads to the exception and one describes the category, i.e., the class, of the it.
The detail description of the exception layers can be found in the
Exception Layers part
of the API documentation. In the following, we briefly describe how to throw an
exception and how to catch it. All the example codes in the below sections can be downloaded at: cntl/exception-usage.cpp.
In HIPP, almost any of the exception classes X has the following features:
It has a super class named like
ErrAppY, which describes the application that leads to the exception.It has a super class named like
ErrClassZ, which describes the category, i.e., the class of the exception.X,ErrAppYandErrClassZare all subclass ofstd::exception.It has a constructor
X(), which accepts an error number typedX::errno_t. The valid error numbers are enumerators inside the class domain defined byX.It has a method
what(), which returns a C-style string constant indicating the detail of the exception. Is has a methodwhats(), which returns astd::stringthat gives more detail of the exception.It has a method
get_errno(), which returns the error number, and a methodset_errno(), which resets the error number.
Throwing and Catching Exceptions
For example, the exception HIPP::ErrLogic is thrown when a general logic error happens.
It has a super class HIPP::ErrAppDefault, which means the logic error is general, not
cause by any specific application. It has a super class HIPP::ErrClassLogic, which
means it belongs to the category of logic error.
To throw such a logic error, just use the the key-word throw. To catch it, just
use the key-word catch. The following codes throw a logic error with an error number
eINVALIDARG indicating that the reason of the error is an invalid argument:
try{
throw HIPP::ErrLogic(HIPP::ErrLogic::eINVALIDARG);
}catch(const HIPP::ErrLogic &e){
HIPP::pout << "Error detail by what(): ", e.what(), '\n',
"Error detail by whats(): ", e.whats(), '\n',
"Error number: ", e.get_errno(), endl;
}
After catching the error, the codes use what() and whats() to get the detail
of the it. whats() is more verbose, but the overhead may be larger. The call of
get_errno() returns the error number eINVALIDARG.
The output is
Error detail by what(): eINVALIDARG
Error detail by whats(): Application: default | Class: logic error | Type: eINVALIDARG
Error number: 3
If an exception is not caught, it propagates upward along the calling chain, unwinds the stack on the chain, and eventually terminates the whole process. In most cases, this is just what you want. However, any well-developed software must take care of these exceptions.
Catching Exceptions by their Application or Category
It is usual that many exceptions can be thrown by a piece of code. Sometimes, you just want to catch any of them, report the detail, and perform some protection procedures before terminating the program.
A simple way is to catch all the exceptions by std::exception. However, HIPP
provides a layered model of exception, so that you can catch exceptions in a
more flexible way. For example, you may want to catch any logic error and
runtime error, but leave other errors un-caught since they may not be recoverable.
You can achieve this by catching the exception HIPP::ErrClass, which
is a super class of both HIPP::ErrLogic and HIPP::ErrRuntime:
try{
throw HIPP::ErrLogic(HIPP::ErrLogic::eINVALIDARG);
throw HIPP::ErrRuntime(HIPP::ErrRuntime::eRANGE);
}catch(const HIPP::ErrClass &e){
HIPP::pout << "Error detail by what(): ", e.what(), '\n',
"Error detail by whats(): ", e.whats(), '\n',
"Error number: ", e.get_errno(), endl;
if( e.get_errno() == e.eLOGIC ){
// Do something for a logic error, e.g.,
HIPP::perr << "A logic error", endl;
}else if( e.get_errno() == e.eRUNTIME ){
// Do something for a runtime error, e.g.,
HIPP::perr << "A runtime error", endl;
}else{
// Other errors, just re-throw.
throw;
}
}
HIPP::ErrClass also has what() and whats() methods which return
the detail of the exception. The get_errno() of it, different from those
of HIPP::ErrLogic and HIPP::ErrRuntime, returns the category
of the exception. You may compare it with any specific category like eLOGIC
or eRUNTIME to check whether it is a logic error
or a runtime error or other categories, and perform necessary procedures for each different case.
The output of above codes is
Error detail by what(): eINVALIDARG
Error detail by whats(): Application: default | Class: logic error | Type: eINVALIDARG
Error number: 4
A logic error