Exceptions - JayhawkZombie/EECS581Project GitHub Wiki
The engine has its own internal exception handling system. This system is designed to allow the programmer to trace exception trains and narrow down causes, as well as provide far more descriptive and helpful error reports.
In SFEngine > Source > Headers > Exceptions > Exceptions.h
The macro definitions
#define EXCEPTION_STRINGIFY(X) #X
#define EXCEPTION_STRING(X) EXCEPTION_STRINGIFY(X)
#define EXCEPTION_FUNC std::string(__func__) + " File: " EXCEPTION_STRING(__FILE__) EXCEPTION_STRING(:) EXCEPTION_STRING(__LINE__) EXCEPTION_STRING(:)
#define EXCEPTION_MESSAGE(STRING) EXCEPTION_FUNC + std::string(STRING) + std::string("\n")
are used to print the file and line at which the exception occurred.
You can use this when throwing an exception, like in BasicLevel.cpp
:
throw StdException({ ExceptionCause::StdException, ExceptionCause::Unknown },
EXCEPTION_MESSAGE("Exception occurred in standard library - unknown cause"));
and a message similar to
SpawnAutoGeneratedObject File: C:\Users\<nope>\Documents\Visual Studio 2015\Projects\SFEngine\Source\Definitions\Level\BasicLevel.cpp :189:Exception occurred in standard library - unknown cause
will be generated.
Each exception object contains a collection of ExceptionCause
enum instances as well as a collection of EXCEPTION_MESSAGE
strings. These are here to help trace the exception stack. These are typically 1-1, but not always.
There is a EngineRuntimeError
exception which derives from std::runtime_error
It has the following constructors:
explicit EngineRuntimeError(const std::vector<ExceptionCause> &causes, const char *message)
explicit EngineRuntimeError(const std::vector<ExceptionCause> &causes, const std::string &string)
virtual const char* what()
virtual void AddCause(const ExceptionCause &cause)
virtual void AddMessage(const std::string &string)
std::string UnwindTrace()
It has the following members:
std::string msg_
std::vector<ExceptionCause> Causes
std::vector<std::string> Messages
There are several exception classes which derive from this:
-
StdException
- used when wrapping an exception thrown by the standard library -
FormattingError
- used when reporting an error in formatting of some kind (you should be very specific in your error message - not be cryptic) -
StreamException
- used when reporting an error in stream interaction. You should be very specific about the action you were trying to take and what caused the exception, if that information is available. -
PhysicsInterfaceException
- used when reporting an error that occurred in the physics engine interface -
DEPRECATED
Exception
- used when reporting a generic std::exception was thrown -
ValueException
- used when reporting that a bad value was received. Try to use this sparingly. If you get input that suggests an error has occurred, then throw. If you can given a value you can handle but just "don't like", don't throw. -
NullPointerException
- used when reporting a nullptr was dereferenced -
InitializationException
- used when reporting that an object failed to be initialized. Throw this if an object cannot be initialized, an error occurs during initialization, or you are told to initialize an object that was already initialized -
InvalidObjectException
- used when reporting that an invalid container was referenced and something tried to use it. -
InvalidParameter
- used when reporting that an invalid parameter was received. Like ValueException, use this sparingly. Only throw if there is an absolute requirement that the parameter be valid (such as when using pointers) -
IDException
- used when reporting that an ID could not be generated when initializing an object or assigning an auto-generated ID. This is probably implying that the globalUsedIDs
structure is getting clogged and a random ID cannot be generated or repeated random values are created too many times and the engine gives up on trying to create one. SeeSFEngine > Source > Definitions > Engine > Externs.cpp : 50, std::uint32_t GenerateID()
for details on the ID generation algorithm -
ConstructionException
- used when reporting that an object failed to construct properly. Generally occurs when the standard library thrown inside a constructor, or data required for the construction for an object is either invalid or missing. Generally speaking, a construction failure is always grounds for a thrown exception unless the object can be done without.
You can throw an exception by:
throw [ExceptionClassName]({ [list of causes] }, EXCEPTION_MESSAGE( [descriptive message] ));
For example, say I was constructing an object and an IDException
was thrown inside the constructor:
MyClass::MyClass(...)
{
try
{
...
}
catch (IDException &exc)
{
//Ughhhhhh
throw ConstructionError({ ExceptionCause::IDGenerationError, ExceptionCause::ConstructionError },
EXCEPTION_MESSAGE("Failed to construct instance of MyClass"));
}
The ExceptionCause
enum provides the following justifications:
InitializationError
- initialization failed
InvalidObjectUsed
- attempted to use an invalid object (dead, frozen, etc)
NullPointer
- nullptr dereferenced
ObjectWasInvalidated
- an object got invalidated somehow, usually by catching an exception from its member and invalidating itself
IDGenerationError
- an ID could not be generated
ConstructionError
- construction failed
SpawnError
- spawning had an error (but construction did not). It may or may not have failed
SpawnFailure
- spawning failed (but construction did not)
InvalidContainer
- an invalid container was used
InvalidParameter
- an invalid (unrecoverable) parameter was received
Catastrophic
- a catastrophic, unrecoverable error occurred
PhysicsInitInvalidData
- invalid data was passed to the physics interface construction methods
PhysicsInitError
- an error occurred in the physics interface init methods
PhysicsUnknown
- an unknown error occurred in the physics engine/interface
DataFormatError
- data was improperly formatted
DataParseError
- data could not be parsed for some reason
StreamError
- an error occurred when using a stream
StreamFailure
- the stream failed to open or is completely invalid and cannot be used
InvalidValue
- an invalid value was received/computed
ValueTooLarge
- value is too large to use
ValueTooSmall
- value is too small to use
ValueNaN
- value is NaN, usually occurs from a division by 0
StdException
- an exception was thrown by the standard library
Unknown
- an unknown error occurred. A very descriptive message should be provided. If possible, add the reason to this enum struct so it can be more accurately reported later