If your C++ compiler does not support exceptions, you will not be able to resume the execution of the application under all circumstances. Until your C++ compiler supports exceptions, you will need to resort to conventional programming techniques to be able to cause resumption in the event of an error.
void function(char const* theString)If an exception is not caught, the function terminate() is called. The default behaviour of the terminate() function is to call the abort() function, which will halt your application and produce a `core' image. If your program needs to do something before halting, you can supply a terminate function which will be called by terminate() when it is invoked. To indicate that your terminate function should be called, you should execute the function set_terminate() in your program, passing to it a pointer to your function. For example, the following has the same end result as the example above.
{
if (theString == 0)
throw exception("Invalid input");
}
main()
{
try
{
function(0);
}
catch (exception)
{
exit(1);
}
}
void function(char const* theString)The terminate function you supply should not return. If the function does return, terminate() will still call the abort() function, resulting in your program being halted.
{
if (theString == 0)
throw exception("Invalid input");
}
void terminate_function()
{
exit(1);
}
main()
{
set_terminate(terminate_function);
function(0);
}
The purpose of the terminate function is to allow you to clean up parts of your application before calling exit(). For example, you may need to remove locks on files, or flush out the contents of any streams. Alternatively, your terminate function could restart the application. You should remember, that your terminate function has been called because an error was encountered, therefore, you should keep to a minimum, anything you do in the terminate function. You should try to avoid accessing any data complex data structures. You should also avoid allocating any new memory while in your terminate function.
If you are using a C++ compiler which does not support exceptions, the library provides the terminate() and set_terminate() functions. When an error is detected, and an exception needs to be thrown, the function terminate() will be called instead. Therefore, although you cannot catch the exceptions, you can specify a terminate function to clean up and either halt or restart the application.
class OTC_ExceptionAny derived classes should redefine the display() member function to dump out to a stream a representation of the exception. As the OTC_Exception base already dumps out some information, your display() function, should call the base class version of the function as the first thing it does. To raise an exception, instead of using throw(), you must use the function OTCLIB_THROW(), passing the exception as an argument. For example:
{
public:
OTC_Exception(char const* theError=0);
// <theError> should be a string
// describing the error which has
// occurred. If <theError> is <0>
// then a description of
// <"Unknown error"> is saved. The
// description of the error will
// be displayed on the logger at
// priority level <ERROR>.
char const* error() const;
// Returns a description of the
// error which has occurred.
virtual void display(ostream& outs) const;
// Dumps a message which composes together
// all the information about the error on the
// stream <outs>. This should be redefined
// in derived class to first call the
// base class version of the function, ie.,
// <OTC_Exception::display()>, and then
// dump out any additional information which
// is kept in the derived class. The derived
// class must terminate each line of
// information with an <endl>.
};
if (theString == 0)or:
OTCLIB_THROW(OTC_Exception("Invalid input"));
if (theString == 0)If your C++ compiler supports exceptions, the OTCLIB_THROW() function will use throw() to raise a true C++ exception of the type you passed to the function. If you wish to know what the exception was, any code which catches the exception should dump a representation of the exception to a stream by calling the display() member function. For example, to display a representation of the exception class to the message log facility, the catch clause would be written as:
{
OTC_Exception exception("Invalid input");
OTCLIB_THROW(exception);
}
catch (OTC_Exception& theException)If your C++ compiler does not support exceptions, a representation of the exception will be automatically displayed via the logger using similar code to that given above. This will be followed by the call to the terminate() function supplied with the library.
{
char theBuffer[2048];
OTC_LogStream theStream(theBuffer,sizeof(theBuffer));
theException.display(theStream);
...
}
#include <OTC/OTC.h>Using the OTCLIB_ENSURE() macro means that you do not have to know if your C++ compiler supports exceptions. If your C++ compiler does support exceptions, the exception class will be thrown. If your C++ compiler does not support exceptions, a description of the exception will be displayed, and the terminate() function supplied with the library will be called instead.
void function(char const* theString)
{
OTCLIB_ENSURE((theString != 0),
"function() - Invalid input");
// ...
}
The first argument to the OTCLIB_ENSURE() macro should be an expression which yields a non zero value if the condition is satisfied. If the condition is not satisfied the expression should yield zero. The second argument to the macro should be a description of why the precondition failed.
As OTCLIB_ENSURE() is a macro, you should avoid using strings in the expression passed as the first argument. This is because not all preprocessors can correctly handle the embedded string when converting the expression into a string, that can be displayed. Both the OTCLIB_ENSURE() macro and otclib_ensure() function may be used in C code.
#include <OTC/OTC.h>Rather than remove assertion checks from code when producing a final version of a program, they can be conditionally compiled out of the program by defining the preprocessor symbol NDEBUG. Because assertions can be compiled out of a program, the expression used in the assertion should not have any side effects on which you rely for the normal operation of your program.
void function(char const* theString)
{
OTCLIB_ASSERT(theString != 0);
// ...
}
If you are using makeit, and it has been installed in the standard manner, using the `opt' variant will automatically result in the NDEBUG symbol being defined by the preprocessor.
If you wish to generate an exception when memory is exhausted, you should add the following to the main() routine of your program.
set_new_handler(otclib_new_handler);When called, the function otclib_new_handler(), will create an exception of type OTCERR_OutOfMemory.
#include <OTC/OTC.h>The type of the exception created is OTC_Exception.
void function(char const* theString)
{
if (theString == 0)
OTCLIB_EXCEPTION("function() - Invalid input");
// ...
}
To specify your exception function, you should call the function OTC_Exception::setThrow() at the start of your main() function, passing it a pointer to your function. Your function must take a single argument of the library exception which is being raised, and return void. For example:
void throwMyException(OTC_Exception const& exception)
{
// throw an exception using home grown mechanism
}
main()
{
OTC_Exception::setThrow()(throwMyException);
// ...
}
An example of using the function in C code is included below. The C code file should include the file `OTC/OTC.h' to access the definition of the OTCLIB_TERMINATE() function.
#include <OTC/OTC.h>
function(theString)
char* theString;
{
if (theString == 0)
OTCLIB_TERMINATE();
// ...
}