FX::FXException Class Reference

#include <FXException.h>

List of all members.


Detailed Description

The base exception class in FOX.

FXException is the base class for exception throws in FOX and is probably one of the most feature rich exception classes on any toolkit for C++. Features include:

Usage is exceptionally easy with levels of support so you can automate as much or little of the generation process as you like. Typical forms include: Automatic retries are easy with try & catch replaced with macros:
FXERRH_TRY
{
   // do something
}
FXERRH_CATCH(FXException &e)
{
   FXERRH_REPORT(parentwnd, e)
}
FXERRH_ENDTRY
You should also replace throw with FXERRH_THROW() though this is usually done for you if you use any of the FXERRH or FXERRG macros.
See also:
FXERRHM(), FXERRHPTR(), FXERRGNF()

Extending exception types

You can subclass FXException to create your own specialised exception types - indeed, Tn does this as do applications I have written which use TnFOX. As of v0.87, FXException is now a destructively copied class rather than the normal exception class it previously was. This was done for two reasons:

  1. FXException grew substantially in size as of v0.87, such that when being thrown up a call stack its large size made copy construction slow, and thus throwing exceptions slow.
  2. There is a most unfortunate bug in MSVC whereby the compiler function stack size calculation routine misunderstands exception objects. It adds up the size of every exception potentially throwable in a function, so if you might FXERRHM()'d say five objects in your function, MSVC adds five times the size of the exception class to the total used. When your exception class is about 16Kb long, you exhaust stack space very, very quickly indeed!

Source munging

FXException has an accompanying source file munging script written in Python called CppMunge.py. This useful tool can automatically extract error code macros as specified in your C++ sources and assign them unique constants into a header file (by default called ErrCodes.h) that are guaranteed to be unique to each class name. This greatly simplifies error handling across entire projects, irrespective of libraries used. You still need to include "ErrCodes.h" in each of your source files using this feature. See this link for more details

Nested Exceptions

The C++ standard states that if an exception is thrown during a stack unwind caused by the handling of an exception throw, the program is to exit immediately via std::terminate() (ie; immediate exit without calling atexit() registrants or anything else). The rationale behind this is that destructors permanently destroy state and so cannot be guaranteed restartable.

This writer personally finds this to be a silly limitation substantially decreasing the reliability of C++ programs using exceptions. While correct design has the programmer wrapping all destructors capable of throwing in a try...catch section, a single missed wrapper causes immediate program exit - a situation which may arise once in a blue moon and thus be missed by testing. What is really needed is to change the C++ spec so that throwing any exception from any destructor is illegal - and then more importantly, have the compiler issue an error if code tries it. This would require modification of the linker symbol mangling system and thus break binary compatibility though.

Furthermore, this writer feels that as soon as you use ANY exceptions in C++, you must write all all destructors to be exception aware because as code grows in size, it becomes impossible to track whether code called by any non-trivial destructor throws or not. Best IMHO to assume that everything can throw, at all times. What annoys me most of all about the C++ standard action of immediately terminating the process is that there is no opportunity for saving out state or even providing debug information.

The C++ source code munger detailed above can optionally insert try...catch(FXException) wraps around each and every destructor it processes (this can be prevented via placing FXERRH_NODESTRUCTORMOD after the destructor definition). The wrap checks to see if an exception is currently being thrown for the current thread and if so, it appends the new exception and sets the FXERRH_HASNESTED and FXERRH_ISFATAL flags. Thus by default the program will report the error, clean up and exit.

Note:
The nested exception framework is disabled during static data initialisation and destruction.

Restarting destructors

It is possible to write restartable destructors in C++ - however, they won't always be of use to you eg; if the object is created on the stack. In that situation, an exception thrown implies unwinding the rest of the stack before it can be handled which clearly implies that that object can no longer exist in any useful sense.

An important point is that the next issue (time of writing: June 2003) of the C++ standard is likely to make all exception throwing from destructors illegal, so if you wish to future-proof your code you want to avoid it.

Static data initialisation and destruction:

A major headache I had was what to do when an exception is thrown during static data initialisation and destruction. Firstly, I'll tell you the received wisdom - just don't do it! - your application is in an undefined state because static data is initialised and destroyed in a random order, so you can't guarantee anything at all! The facilities provided by FX::FXProcess_StaticInit are there precisely to permit non-trivial static data initialisation and destruction, so use them!

However, sometimes you can't escape running non-trivial code and it's better to reuse the library rather than duplicate the functionality in non-throwing code. For this situation I've had FXException print its report to stderr on construction if static data is unavailable and it also disables its nested exception functionality (because it requires holding static state). This should cover informing the user of a problem rather than the generic and unhelpful message you usually get when terminate() gets called.

Good practice in exception using C++:

First cardinal rule of all is to always assume every line of code can throw an exception. Not trying to be clever will prevent nasty bugs!

Definition at line 378 of file FXException.h.

Public Member Functions

 FXException (const char *_filename, const char *_function, int _lineno, const FXString &_msg, FXuint _code, FXuint _flags)
 FXException ()
FXDEPRECATEDEXT FXException (const FXchar *msg)
FXExceptionoperator= (FXException &o)
 FXException (FXException &o)
FXException copy () const
bool isValid () const throw ()
bool isFatal () const throw ()
void setFatal (bool _fatal)
void sourceInfo (const char **FXRESTRICT file, const char **FXRESTRICT function, int *FXRESTRICT lineno) const throw ()
const FXStringmessage () const throw ()
void setMessage (const FXString &msg)
FXuint code () const throw ()
FXuint flags () const throw ()
FXulong threadId () const throw ()
const FXStringreport () const
FXDEPRECATEDEXT const FXcharwhat () const
bool isPrimary () const
FXint nestedLen () const
FXException nested (FXint idx) const
virtual ~FXException ()

Static Public Member Functions

static FXint setGlobalErrorCreationCount (FXint no)
static bool setConstructionBreak (bool v)
static FXDLLLOCAL void int_enableNestedExceptionFramework (bool yes=true)
static void int_setThrownException (FXException &e)
static void int_enterTryHandler (const char *srcfile, const char *function, int lineno)
static void int_exitTryHandler () throw ()
static void int_incDestructorCnt ()
static bool int_nestedException (FXException &e)
static void int_decDestructorCnt ()
static bool int_testCondition ()
static void int_throwWinError (const char *file, const char *function, int lineno, FXuint code, FXuint flags, const FXString &filename=FXString::nullStr())
static void int_throwOSError (const char *file, const char *function, int lineno, int code, FXuint flags, const FXString &filename=FXString::nullStr())

Friends

FXAPI FXStreamoperator<< (FXStream &s, const FXException &i)
FXAPI FXStreamoperator>> (FXStream &s, FXException &i)


The documentation for this class was generated from the following file:
(C) 2002-2009 Niall Douglas. Some parts (C) to assorted authors.
Generated on Fri Nov 20 18:33:37 2009 for TnFOX by doxygen v1.4.7