|
OODuck
0.5
C Oriented Object framework with duck-typing support
|
Exceptions4C library. More...
Files | |
| file | e4c.h |
Classes | |
| struct | e4c_exception_type |
| struct | e4c_exception |
| struct | e4c_signal_mapping |
Typedefs | |
| typedef void(* | e4c_uncaught_handler) (const e4c_exception *exception) |
| typedef void *(* | e4c_initialize_handler) (const e4c_exception *exception) |
| typedef void(* | e4c_finalize_handler) (void *custom_data) |
Enumerations | |
| enum | e4c_status_ { e4c_succeeded, e4c_recovered, e4c_failed } |
Exception handling keywords | |
This set of keywords express the semantics of exception handling. | |
| #define | try E4C_TRY |
| #define | catch(exception_type) E4C_CATCH(exception_type) |
| #define | finally E4C_FINALLY |
| #define | retry(max_retry_attempts) E4C_RETRY(max_retry_attempts) |
| #define | throw(exception_type, message) E4C_THROW(exception_type, message) |
| #define | rethrow(message) E4C_RETHROW(message) |
Dispose pattern keywords | |
This set of keywords express the semantics of automatic resource acquisition and disposal. | |
| #define | with(resource, dispose) E4C_WITH(resource, dispose) |
| #define | use E4C_USE |
| #define | using(type, resource, args) E4C_USING(type, resource, args) |
| #define | reacquire(max_reacquire_attempts) E4C_REACQUIRE(max_reacquire_attempts) |
Integration macros | |
These macros are designed to ease the integration of external libraries which make use of the exception handling system. | |
| #define | E4C_VERSION_NUMBER |
| #define | E4C_VERSION_THREADSAFE |
| #define | E4C_VERSION_MAJOR |
| #define | E4C_VERSION_MINOR |
| #define | E4C_VERSION_REVISION |
| #define | E4C_VERSION_STRING |
| #define | E4C_EXCEPTION_MESSAGE_SIZE 128 |
| #define | e4c_reusing_context(status, on_failure) E4C_REUSING_CONTEXT(status, on_failure) |
| #define | E4C_ON_FAILURE(handler) handler( e4c_get_exception() ) |
| #define | E4C_NO_RETURN |
| #define | E4C_UNREACHABLE_RETURN(value) |
| #define | E4C_UNREACHABLE_VOID_RETURN |
Other convenience macros | |
These macros provide a handy way to: begin (and end) implicitly a new exception context, express assertions, define and declare exceptions, and define arrays of signal mappings. | |
| #define | e4c_using_context(handle_signals) E4C_USING_CONTEXT(handle_signals) |
| #define | assert(condition) E4C_ASSERT(condition) |
| #define | E4C_DECLARE_EXCEPTION(name) |
| #define | E4C_DEFINE_EXCEPTION(name, default_message, supertype) |
| #define | E4C_SIGNAL_MAPPING(signal_number, exception_type) |
| #define | E4C_IGNORE_SIGNAL(signal_number) |
| #define | E4C_NULL_SIGNAL_MAPPING |
Predefined signal mappings | |
There is a predefined set of signal mappings. Signal mappings are used to convert signals into exceptions. Common signals are mapped to its corresponding exception, for example:
| |
| const e4c_signal_mapping *const | e4c_default_signal_mappings |
Predefined exceptions | |
Built-in exceptions represent usual error conditions that might occur during the course of any program. They are organized into a pseudo-hierarchy; | |
| E4C_DECLARE_EXCEPTION (RuntimeException) | |
| E4C_DECLARE_EXCEPTION (NotEnoughMemoryException) | |
| E4C_DECLARE_EXCEPTION (IllegalArgumentException) | |
| E4C_DECLARE_EXCEPTION (AssertionException) | |
| E4C_DECLARE_EXCEPTION (InputOutputException) | |
| E4C_DECLARE_EXCEPTION (SignalException) | |
| E4C_DECLARE_EXCEPTION (SignalAlarmException) | |
| E4C_DECLARE_EXCEPTION (SignalChildException) | |
| E4C_DECLARE_EXCEPTION (SignalTrapException) | |
| E4C_DECLARE_EXCEPTION (ErrorSignalException) | |
| E4C_DECLARE_EXCEPTION (IllegalInstructionException) | |
| E4C_DECLARE_EXCEPTION (ArithmeticException) | |
| E4C_DECLARE_EXCEPTION (BrokenPipeException) | |
| E4C_DECLARE_EXCEPTION (BadPointerException) | |
| E4C_DECLARE_EXCEPTION (NullPointerException) | |
| E4C_DECLARE_EXCEPTION (ControlSignalException) | |
| E4C_DECLARE_EXCEPTION (StopException) | |
| E4C_DECLARE_EXCEPTION (KillException) | |
| E4C_DECLARE_EXCEPTION (HangUpException) | |
| E4C_DECLARE_EXCEPTION (TerminationException) | |
| E4C_DECLARE_EXCEPTION (AbortException) | |
| E4C_DECLARE_EXCEPTION (CPUTimeException) | |
| E4C_DECLARE_EXCEPTION (UserControlSignalException) | |
| E4C_DECLARE_EXCEPTION (UserQuitException) | |
| E4C_DECLARE_EXCEPTION (UserInterruptionException) | |
| E4C_DECLARE_EXCEPTION (UserBreakException) | |
| E4C_DECLARE_EXCEPTION (ProgramSignalException) | |
| E4C_DECLARE_EXCEPTION (ProgramSignal1Exception) | |
| E4C_DECLARE_EXCEPTION (ProgramSignal2Exception) | |
Exception context handling functions | |
These functions enclose the scope of the exception handling system and retrieve the current exception context. | |
| E4C_BOOL | e4c_context_is_ready (void) |
| void | e4c_context_begin (E4C_BOOL handle_signals) |
| void | e4c_context_end (void) |
| void | e4c_context_set_handlers (e4c_uncaught_handler uncaught_handler, void *custom_data, e4c_initialize_handler initialize_handler, e4c_finalize_handler finalize_handler) |
| void | e4c_context_set_signal_mappings (const e4c_signal_mapping *mappings) |
| const e4c_signal_mapping * | e4c_context_get_signal_mappings (void) |
| e4c_status | e4c_get_status (void) |
| const e4c_exception * | e4c_get_exception (void) |
Other integration and convenience functions | |
| long | e4c_library_version (void) |
| E4C_BOOL | e4c_is_instance_of (const e4c_exception *instance, const e4c_exception_type *exception_type) |
| void | e4c_print_exception (const e4c_exception *exception) |
| void | e4c_print_exception_type (const e4c_exception_type *exception_type) |
Exceptions4C library.
| #define assert | ( | condition | ) | E4C_ASSERT(condition) |
Expresses a program assertion
| condition | A predicate that must evaluate to true |
An assertion is a mechanism to express that the developer thinks that a specific condition is always met at some point of the program.
assert is a convenient way to insert debugging assertions into a program. The NDEBUG compile-time parameter determines whether the assumptions will be actually verified by the program at run-time.
In presence of NDEBUG, the assertion statements will be ignored and therefore will have no effects on the program, not even evaluating the condition. Therefore expressions passed to assert must not contain side-effects, since they will not take place when debugging is disabled.
In absence of NDEBUG, the assertion statements will verify that the condition is met every time the program reaches that point of the program.
If the assertion does not hold at any time, then an #AssertionException will be thrown to indicate the programming error. This exception cannot be caught whatsoever. The program (or current thread) will be terminated.
The main advantage of using this assertion mechanism (as opposed to the macros provided by the standard header file assert.h) is that all of the pending finally blocks will be executed, before actually exiting the program or thread.
assert. Such programming error will lead to an abrupt exit of the program (or thread).| #define catch | ( | exception_type | ) | E4C_CATCH(exception_type) |
Introduces a block of code capable of handling a specific type of exceptions
| exception_type | The type of exceptions to be handled |
catch blocks are optional code blocks that must be preceded by try, with... use or using blocks. Several catch blocks can be placed next to one another.
When an exception is thrown, the system looks for a catch block to handle it. The first capable block (in order of appearance) will be executed. The exception is said to be caught and the try block is in recovered (status)[@ ref e4c_status].
The caught exception can be accessed through the function e4c_get_exception.
The actual type of the exception can be checked against other exception types through the function e4c_is_instance_of.
The type might also be compared directly against another specific exception type.
After the catch block completes, the finally block (if any) is executed. Then the program continues by the next line following the set of try... catch... finally blocks.
However, if an exception is thrown in a catch block, then the finally block will be executed right away and the system will look for an outter catch block to handle it.
Only one of all the catch blocks will be executed for each try block, even though the executed catch block throws another exception. The only possible way to execute more than one catch block would be by retrying the entire try block.
| #define E4C_DECLARE_EXCEPTION | ( | name | ) |
Throws an exception with a formatted message
| exception_type | The type of exception to be thrown |
| format | The string containing the specifications that determine the output format for the variadic arguments |
| ... | The variadic arguments that will be formatted according to the format control |
This is a handy way to compose a formatted message and throw an exception on the fly:
This macro relies on two features that were introduced in the ISO/IEC 9899:1999 (also known as C99) revision of the C programming language standard in 1999:
vsnprintfIn order not to create compatibility issues, this macro will only be defined when the __STDC_VERSION__ compile-time parameter is defined as a long value greater than or equal to 199901L, or when HAVE_C99_VARIADIC_MACROS is defined.
The semantics of this keyword are the same as for throw.
throwf. Such programming error will lead to an abrupt exit of the program (or thread).vsnprintf with the specified format and variadic arguments. For further information on formatting rules, you may look up the specifications for the function vsnprintf. throwf point.| format | The string containing the specifications that determine the output format for the variadic arguments. |
| ... | The variadic arguments that will be formatted according to the format control. |
This is a handy way to create (and then throw) a new instance of the currently thrown exception, with a more specific, formatted message.
This macro relies on two features that were introduced in the ISO/IEC 9899:1999 (also known as C99) revision of the C programming language standard in 1999:
vsnprintfIn order not to create compatibility issues, this macro will only be defined when the __STDC_VERSION__ compile-time parameter is defined as a long value greater than or equal to 199901L, or when HAVE_C99_VARIADIC_MACROS is defined.
The semantics of this keyword are the same as for throw.
rethrowf. Such programming error will lead to an abrupt exit of the program (or thread).vsnprintf with the specified format and variadic arguments. For further information on formatting rules, you may look up the specifications for the function vsnprintf. rethrowf point.| name | Name of the exception type |
This macro introduces the name of an extern, const exception type which will be available to be thrown or caught:
This macro is intended to be used inside header files.
E4C_DEFINE_EXCEPTION.| #define E4C_DEFINE_EXCEPTION | ( | name, | |
| default_message, | |||
| supertype | |||
| ) |
Defines an exception type
| name | Name of the new exception type |
| default_message | Default message of the new exception type |
| supertype | Supertype of the new exception type |
This macro allocates a new, const exception type.
This macro is intended to be used inside sorce code files. The defined exception types can be declared in a header file through the macro E4C_DECLARE_EXCEPTION.
| #define E4C_EXCEPTION_MESSAGE_SIZE 128 |
Provides the maximum length (in bytes) of an exception message
| #define E4C_IGNORE_SIGNAL | ( | signal_number | ) |
Ignores a specific signal number
| signal_number | Numeric value of the signal to be ignored |
This macro represents a signal mapping literal. It comes in handy for initializing arrays of signal mappings.
| #define E4C_NO_RETURN |
Marks a function which never returns
This macro helps both developer and compiler to assume that the marked function will not return the control to its caller (unless by throwing an exception).
void.For example, a function f1 that always throws an exception, could be marked with this macro:
Then, if another function tested a condition and then called f1, it wouldn't need to return anything witnin the if branch, nor consider the else branch of the test:
If the compiler supports this macro, it could optimize the program and avoid spurious warnings of uninitialized variables.
| #define E4C_NULL_SIGNAL_MAPPING |
Represents a null signal mapping literal
This macro represents a null signal mapping literal. It comes in handy for terminating arrays of #e4c_signal_mapping.
| #define E4C_ON_FAILURE | ( | handler | ) | handler( e4c_get_exception() ) |
Provides a means of parsing an exception to obtain a status value
| handler | The name of the parser function to be called |
This is a handy way to call a function when a e4c_reusing_context block fails. This function will be passed the current thrown exception; it is expected to parse it and return a proper status value.
| #define e4c_reusing_context | ( | status, | |
| on_failure | |||
| ) | E4C_REUSING_CONTEXT(status, on_failure) |
Reuses an existing exception context, otherwise, begins a new one and then ends it.
| status | The name of a previously defined variable, or lvalue, which will be assigned the specified failure value |
| on_failure | A constant value or expression that will be assigned to the specified lvalue in case of failure |
This macro lets library developers use the exception framework, regardless of whether the library clients are unaware of the exception handling system. In a nutshell, function libraries can use try, catch, throw, etc. whether the client previously began an exception context or not.
You must not use this macro unless you are implementing some functionality which is to be called from another program, potentially unaware of exceptions.
When the block completes, the system returns to its previous status (if it was required to open a new exception context, then it will be automatically closed).
This way, when an external function encounters an error, it may either throw an exception (when the caller is aware of the exception system), or otherwise return an error code (when the caller did not open an exception context).
e4c_reusing_context takes two parameters:
status (lvalue)on_failure (rvalue)status must will be assigned on_failure if, and only if, an exception is thrown inside the block. Needless to say, on_failure may be an expression assignable to status.
status will be left unmodified if the client (i.e. the function caller) is exception-aware, or the block completes without an error (i.e. no exception is thrown), so it must be properly initialized before returning it.
Please note that status doesn't have to be just a dichotomy (success or failure). It can be a fine-grained value describing what exactly went wrong. You can pass any expression to e4c_reusing_context as on_failure; it will be evaluated when an exception is thrown:
However, Most of the times you probably want to yield a different status value depending on the specific exception being thrown. This can be easily accomplished by making use of the macro E4C_ON_FAILURE.
Next, the semantics of e4c_reusing_context are explained, step by step:
status will be asigned the value of the expression on_failure.If you need to perform any cleanup, you should place it inside a finally block.
If you need to rely on the signal handling system, you may call e4c_context_set_signal_mappings explicitly. You should take into account that you could be hijacking your client's original signal mappings, so you should also call e4c_context_get_signal_mappings in order to restore the previous signal mappings when you are done.
This macro only begins a new exception context if there is no one, already begun, to be used whereas e4c_using_context always attempts to begin a new one.
e4c_reusing_context must not be exited through any of: goto, break, continue or return (but it is legal to throw an exception). e4c_reusing_context is guaranteed to take place inside an exception context.| #define E4C_SIGNAL_MAPPING | ( | signal_number, | |
| exception_type | |||
| ) |
Maps a specific signal number to a given exception type
| signal_number | Numeric value of the signal to be converted |
| exception_type | Exception type representing the signal |
This macro represents a signal mapping literal. It comes in handy for initializing arrays of signal mappings.
| #define E4C_UNREACHABLE_RETURN | ( | value | ) |
Simulates a function return
| value | The value that would be returned if the statement took place. |
This macro ensures portability on compilers which don't support functions that never return.
It may be used after calling a function marked as E4C_NO_RETURN, so that the compiler will not complain about control reaching end of non-void function. For example:
This macro will become an actual return statement if the compiler does not support E4C_NO_RETURN, even though it will never be reached (because the called function won't actually return control).
| #define E4C_UNREACHABLE_VOID_RETURN |
Simulates a function void return
This macro ensures portability on static source code analyzers which don't support functions that never return.
It may be used after calling a function marked as E4C_NO_RETURN, so that the analyzer will not complain about spurious errors. For example, if we didn't use E4C_UNREACHABLE_VOID_RETURN here, some analyzers might complain about possible null pointer dereference at line foo = *bar, because they are not aware that function call f1(321); will never return control:
This macro will become an actual return statement if the compiler does not support E4C_NO_RETURN, even though it will never be reached (because the called function won't actually return control).
| #define e4c_using_context | ( | handle_signals | ) | E4C_USING_CONTEXT(handle_signals) |
Introduces a block of code which will use a new exception context.
| handle_signals | If true, the signal handling system will be set up with the default mapping. |
This macro begins a new exception context to be used by the code block right next to it. When the code completes, e4c_context_end will be called implicitly.
This macro is very convenient when the beginning and the ending of the current exception context are next to each other. For example, there is no semantic difference between this two blocks of code:
This macro always attempts to begin a new exception context, whereas e4c_reusing_context only does if there is no exception context, already begun, to be used.
This macro should be used whenever possible, rather than doing the explicit, manual calls to e4c_context_begin and e4c_context_end, because it is less prone to errors.
e4c_using_context must not be exited through any of: goto, break, continue or return (but it is legal to throw an exception). e4c_using_context is guaranteed to take place inside an exception context.| #define E4C_VERSION_MAJOR |
Provides the library major version number
The library major version number is an int value which is incremented from one release to another when there are significant changes in functionality.
| #define E4C_VERSION_MINOR |
Provides the library minor version number
The library minor version number is an int value which is incremented from one release to another when only minor features or significant fixes have been added.
| #define E4C_VERSION_NUMBER |
Provides the library version number
The library version number is a long value which expresses:
The multi-thread (or thread-safe) mode can be enabled by compiling the library with the E4C_THREADSAFE compile-time parameter.
The formula to encode these version numbers into a single long value is:
These numbers can be obtained separately through the next macros:
The library version number can be also obtained as a string literal in the format "MAJOR.MINOR.REVISION (THREADSAFE)" through the macro E4C_VERSION_STRING.
e4c_library_version.| #define E4C_VERSION_REVISION |
Provides the library revision number
The library revision number is an int value which is incremented from one release to another when minor bugs are fixed.
| #define E4C_VERSION_STRING |
Provides the library version number as a string literal
The format of the string literal is: "MAJOR.MINOR.REVISION (THREADSAFE)".
| #define E4C_VERSION_THREADSAFE |
Provides the library thread mode (either single-thread or multi-thread)
When the library is compiled with the E4C_THREADSAFE compile-time parameter, E4C_VERSION_THREADSAFE will yield the int value 1 (meaning multi-thread mode), otherwise it will yield the int value 0 (meaning single-thread mode).
| #define finally E4C_FINALLY |
Introduces a block of code responsible for cleaning up the previous exception-aware block
finally blocks are optional code blocks that must be preceded by try, with... use or using blocks. It is allowed to place, at most, one finally block for each one of these.
The finally block can determine the completeness of the exception-aware block through the function e4c_get_status. The thrown exception (if any) can also be accessed through the function e4c_get_exception.
The finally block will be executed only once. The only possible way to execute it again would be by retrying the entire try block.
finally block must be preceded by a try, with... use, using or catch block.finally block must not be exited through any of: goto, break, continue or return (but it is legal to throw an exception). finally. Such programming error will lead to an abrupt exit of the program (or thread).| #define reacquire | ( | max_reacquire_attempts | ) | E4C_REACQUIRE(max_reacquire_attempts) |
Repeats the previous with block entirely
| max_reacquire_attempts | The maximum number of attempts to reacquire |
This macro discards any thrown exception (if any) and repeats the previous with block, up to a specified maximum number of attempts. If the acquisition completes, then the use block will be executed.
It is intended to be used within catch or finally blocks, next to a with... use or using block, when the resource acquisition fails, as a quick way to fix an error condition and try to acquire the resource again.
with block can eventually be attempted an unlimited number of times. Care should be taken in order not to create an infinite loop.Once the resource has been acquired, the use block can also be repeated alone through the keyword retry:
reacquire keyword must be used from a catch or finally block, preceded by with... use or using blocks.reacquire. Such programming error will lead to an abrupt exit of the program (or thread). with block has already been attempted, at least, the specified maximum number of times.| #define rethrow | ( | message | ) | E4C_RETHROW(message) |
Throws again the currently thrown exception, with a new message
| message | The new message describing the exception. It should be more specific than the current one |
This macro creates a new instance of the thrown exception, with a more specific message.
rethrow is intended to be used within a catch block; the purpose is to refine the message of the currently caught exception. The previous exception (and its message) will be stored as the cause of the newly thrown exception.
The semantics of this keyword are the same as for throw.
rethrow. Such programming error will lead to an abrupt exit of the program (or thread). rethrow point.| #define retry | ( | max_retry_attempts | ) | E4C_RETRY(max_retry_attempts) |
Repeats the previous try (or use) block entirely
| max_retry_attempts | The maximum number of attempts to retry |
This macro discards any thrown exception (if any) and repeats the previous try or use block, up to a specified maximum number of attempts. It is intended to be used within catch or finally blocks as a quick way to fix an error condition and try again.
If the block has already been tried at least the specified number of times, then the program continues by the next line following retry clause.
This macro won't return control unless the block has already been attempted, at least, the specified maximum number of times.
catch code block is being executed, the current exception is considered caught. If you want the exception to be propagated when the maximum number of attempts has been reached, then you need to rethrow it.finally block, the current exception (if any) will be propagated when the retry does not take place, so you don't need to rethrow it again.retry. Such programming error will lead to an abrupt exit of the program (or thread).retry keyword must be used from a catch or finally block. retry point, unless the try (or use) block has already been attempted, at least, the specified number of times.| #define throw | ( | exception_type, | |
| message | |||
| ) | E4C_THROW(exception_type, message) |
Signals an exceptional situation represented by an exception object
| exception_type | The type of exception to be thrown |
| message | The ad-hoc message describing the exception. If NULL, then the default message for the specified exception type will be used |
Creates a new instance of the specified type of exception and then throws it. The message is copied into the thrown exception, so it may be freely deallocated. If NULL is passed, then the default message for that type of exception will be used.
When an exception is thrown, the exception handling framework looks for the appropriate catch block that can handle the exception. The system unwinds the call chain of the program and executes the finally blocks it finds.
When no catch block is able to handle an exception, the system eventually gets to the main function of the program. This situation is called an uncaught exception.
throw. Such programming error will lead to an abrupt exit of the program (or thread). throw point.| #define try E4C_TRY |
Introduces a block of code aware of exceptions
A try statement executes a block of code. If an exception is thrown and there is a catch block that can handle it, then control will be transferred to it. If there is a finally block, then it will be executed, no matter whether the try block completes normally or abruptly, and no matter whether a catch block is first given control.
The block of code immediately after the keyword try is called the try block of the try statement. The block of code immediately after the keyword finally is called the finally block of the try statement.
One try block may precede many catch blocks (also called exception handlers). A catch block must have exactly one parameter, which is the exception type it is capable of handling. Within the catch block, the exception can be accessed through the function e4c_get_exception. Exception handlers are considered in left-to-right order: the earliest possible catch block handles the exception. If no catch block can handle the thrown exception, it will be propagated.
Sometimes it may come in handy to retry an entire try block; for instance, once the exception has been caught and the error condition has been solved.
A try block has an associated status according to the way it has been executed:
catch block handles it.The status of the current try block can be retrieved through the function e4c_get_status.
try. Such programming error will lead to an abrupt exit of the program (or thread).try block must precede, at least, another block of code, introduced by either catch or finally.try block may precede several catch blocks.try block can precede, at most, one finally block.try block must not be exited through any of: goto, break, continue or return (but it is legal to throw an exception).finally block will be executed after the try block and any catch block that might be executed, no matter whether the try block succeeds, recovers or fails.| #define use E4C_USE |
Closes a block of code with automatic disposal of a resource
A use block must always be preceded by a with block. These two keywords are designed so the compiler will complain about dangling with... use blocks.
A code block introduced by the use keyword will only be executed if, and only if, the acquisition of the resource completes without exceptions.
The disposal function will be executed, either if the use block completes or not.
use block must be preceded by a with block.use block must not be exited through any of: goto, break, continue or return (but it is legal to throw an exception).| #define using | ( | type, | |
| resource, | |||
| args | |||
| ) | E4C_USING(type, resource, args) |
Introduces a block of code with automatic acquisition and disposal of a resource
| type | The type of the resource |
| resource | The resource to be acquired, used and then disposed |
| args | A list of arguments to be passed to the acquisition function |
The specified resource will be acquired, used and then disposed. The automatic acquisition and disposal is achieved by calling the implicit functions e4c_acquire_type and e4c_dispose_type:
TYPE e4c_acquire_TYPE(ARGS)void e4c_dispose_TYPE(TYPE RESOURCE, E4C_BOOL failed)These two symbols must exist, in the form of either functions or macros.
The semantics of the automatic acquisition and disposal are the same as for blocks introduced by with... use. For example, a using block can also precede catch and finally blocks.
using. Such programming error will lead to an abrupt exit of the program (or thread).using block must not be exited through any of: goto, break, continue or return (but it is legal to throw an exception).| #define with | ( | resource, | |
| dispose | |||
| ) | E4C_WITH(resource, dispose) |
Opens a block of code with automatic disposal of a resource
| resource | The resource to be disposed |
| dispose | The name of the disposal function (or macro) |
The combination of keywords with... use encapsules the Dispose Pattern. This pattern consists of two separate blocks and an implicit call to a given function:
with block is responsible for the resource acquisitionuse block makes use of the resourceA with block must be followed by a use block. In addition, the use block may be followed by several catch blocks and/or one finally block.
The with keyword guarantees that the disposal function will be called if, and only if, the acquisition block is completed without any errors (i.e. the acquisition block does not throw any exceptions).
If the with block does not complete, neither the disposal function nor the use block will be executed.
The disposal function is called right after the use block. If an exception is thrown, the catch or finally blocks (if any) will take place after the disposal of the resource.
When called, the disposal function will receive two arguments:
use block failed (i. e. did not complete)This way, different actions can be taken depending on the success or failure of the block. For example, commiting or rolling back a transaction resource.
Legacy functions can be reused by defining macros. For example, a file resource needs to be closed regardless of the errors occurred. Since the function fclose only takes one parameter, we could define the next macro:
Here is the typical usage of with... use:
Nonetheless, one-liners fit nicely too:
There is a way to lighten up even more this pattern by defining convenience macros, customized for a specific kind of resources. For example, #e4c_using_file or #e4c_using_memory.
with. Such programming error will lead to an abrupt exit of the program (or thread).with block must not be exited through any of: goto, break, continue or return (but it is legal to throw an exception).with block must always be followed by a use block.| typedef void(* e4c_finalize_handler) (void *custom_data) |
Represents a function which will be executed whenever an exception is destroyed.
| custom_data | The "custom data" of the exception to be discarded |
When this handler is set, it will be called any time an exception is discarded. It will be passed the custom_data of the exception, so it may dispose resources previously acquired by the initialize handler.
This handler can be set through the function e4c_context_set_handlers:
| typedef void*(* e4c_initialize_handler) (const e4c_exception *exception) |
Represents a function which will be executed whenever a new exception is thrown.
| exception | The newly thrown exception |
When this handler is set, it will be called any time a new exception is created. The void pointer returned by this function will be assigned to the exception's custom_data. This data can be accessed later on, for example, from a catch block, or an uncaught handler, for any specific purpose.
This handler can be set through the function e4c_context_set_handlers:
By the time this handler is called, the exception already has been assigned the initial value specified for custom_data, so the handler may make use of it:
| typedef void(* e4c_uncaught_handler) (const e4c_exception *exception) |
Represents a function which will be executed in the event of an uncaught exception.
| exception | The uncaught exception |
This handler can be set through the function e4c_context_set_handlers:
There exists a convenience function e4c_print_exception which is used as the default uncaught handler, unless otherwise specified. It simply prints information regarding the exception to stderr.
| enum e4c_status_ |
Represents the completeness of a code block aware of exceptions
The symbolic values representing the status of a block help to distinguish between different possible situations inside a finally block. For example, different cleanup actions can be taken, depending on the status of the block.
| Enumerator | |
|---|---|
| e4c_succeeded |
There were no exceptions |
| e4c_recovered |
There was an exception, but it was caught |
| e4c_failed |
There was an exception and it wasn't caught |
| void e4c_context_begin | ( | E4C_BOOL | handle_signals | ) |
Begins an exception context
| handle_signals | If true, the signal handling system will be set up with the default mapping. |
This function begins the current exception context to be used by the program (or current thread), until e4c_context_end is called.
The signal handling system can be initialized automatically with the default signal mappings by passing handle_signals=true. This is equivalent to:
signal function might be undefined for a multithreaded program, so use the signal handling system with caution.The convenience function e4c_print_exception will be used as the default uncaught handler. It will be called in the event of an uncaught exception, before exiting the program or thread. This handler can be set through the function e4c_context_set_handlers.
e4c_context_begin is called, the program (or thread) must call e4c_context_end before exiting.e4c_context_begin twice in a row is considered a programming error, and therefore the program (or thread) will exit abruptly. Nevertheless, e4c_context_begin can be called several times if, and only if, e4c_context_end is called in between.| void e4c_context_end | ( | void | ) |
Ends the current exception context
This function ends the current exception context.
e4c_context_end. Such programming error will lead to an abrupt exit of the program (or thread).| const e4c_signal_mapping* e4c_context_get_signal_mappings | ( | void | ) |
Retrieves the signal mappings for the current exception context
This function retrieves the current array of mappings between the signals to be handled and the corresponding exception to be thrown.
e4c_context_get_signal_mappings. Such programming error will lead to an abrupt exit of the program (or thread).| E4C_BOOL e4c_context_is_ready | ( | void | ) |
Checks if the current exception context is ready
This function returns whether there is an actual exception context ready to be used by the program or current thread.
| void e4c_context_set_handlers | ( | e4c_uncaught_handler | uncaught_handler, |
| void * | custom_data, | ||
| e4c_initialize_handler | initialize_handler, | ||
| e4c_finalize_handler | finalize_handler | ||
| ) |
Sets the optional handlers of an exception context
| uncaught_handler | The function to be executed in the event of an uncaught exception |
| custom_data | The initial value assigned to the custom_data of a new exception |
| initialize_handler | The function to be executed whenever a new exception is thrown |
| finalize_handler | The function to be executed whenever an exception is destroyed |
These handlers are a means of customizing the behavior of the exception system. For example, you can specify what needs to be done when a thrown exception is not caught (and thus, the program or thread is about to end) by calling e4c_context_set_handlers with your own uncaught handler.
You can also control the custom data attached to any new exception by specifying any or all of these:
custom_datacustom_datacustom_dataWhen these handlers are defined, they will be called anytime an exception is uncaught, created or destroyed. You can use them to meet your specific needs. For example, you could...
e4c_context_set_handlers. Such programming error will lead to an abrupt exit of the program (or thread).| void e4c_context_set_signal_mappings | ( | const e4c_signal_mapping * | mappings | ) |
Assigns the specified signal mappings to the exception context
| mappings | The array of mappings |
This function assigns an array of mappings between the signals to be handled and the corresponding exception to be thrown.
signal function might be undefined for a multithreaded program, so use the signal handling system with caution.e4c_context_set_signal_mappings. Such programming error will lead to an abrupt exit of the program (or thread).mappings must be terminated by E4C_NULL_SIGNAL_MAPPING.| E4C_DECLARE_EXCEPTION | ( | RuntimeException | ) |
This is the root of the exception pseudo-hierarchy
#RuntimeException is the common supertype of all exceptions.
| E4C_DECLARE_EXCEPTION | ( | NotEnoughMemoryException | ) |
This exception is thrown when the system runs out of memory
#NotEnoughMemoryException is thrown when there is not enough memory to continue the execution of the program.
| E4C_DECLARE_EXCEPTION | ( | IllegalArgumentException | ) |
This exception is thrown when a function is passed an illegal or inappropriate argument
#IllegalArgumentException is thrown by a function when it detects that some of the function parameters (passed by the caller) is unacceptable.
| E4C_DECLARE_EXCEPTION | ( | AssertionException | ) |
This exception is thrown when an assertion does not hold
#AssertionException is part of the assertion facility of the library. It is thrown when the compile-time parameter NDEBUG is present and the conditon of an assertion evaluates to false.
finally blocks.| E4C_DECLARE_EXCEPTION | ( | InputOutputException | ) |
This exception is thrown when an input/output error occurs
#InputOutputException is the general type of exceptions produced by failed or interrupted I/O operations.
| E4C_DECLARE_EXCEPTION | ( | SignalException | ) |
This exception is the common supertype of all signal exceptions
Signal exceptions are thrown when some signal is sent to the process.
A signal can be generated by calling raise.
| E4C_DECLARE_EXCEPTION | ( | SignalAlarmException | ) |
This exception is thrown when a time limit has elapsed
#SignalAlarmException represents SIGALRM, the signal sent to a process when a time limit has elapsed.
| E4C_DECLARE_EXCEPTION | ( | SignalChildException | ) |
This exception is thrown when a child process terminates
#SignalChildException represents SIGCHLD, the signal sent to a process when a child process terminates.
| E4C_DECLARE_EXCEPTION | ( | SignalTrapException | ) |
This exception is thrown when a condition arises that a debugger has requested to be informed of
#SignalTrapException represents SIGTRAP, the signal sent to a process when a condition arises that a debugger has requested to be informed of.
| E4C_DECLARE_EXCEPTION | ( | ErrorSignalException | ) |
This exception is the common supertype of all error signal exceptions
Error signal exceptions are thrown when some error prevents the program to keep executing its normal flow.
| E4C_DECLARE_EXCEPTION | ( | IllegalInstructionException | ) |
This exception is thrown when the process attempts to execute an illegal instruction
#IllegalInstructionException represents SIGILL, the signal sent to a process when it attempts to execute a malformed, unknown, or privileged instruction.
| E4C_DECLARE_EXCEPTION | ( | ArithmeticException | ) |
This exception is thrown when the process performs an erroneous arithmetic operation
#ArithmeticException represents SIGFPE, the signal sent to a process when it performs an erroneous arithmetic operation.
| E4C_DECLARE_EXCEPTION | ( | BrokenPipeException | ) |
This exception is thrown when the process attempts to write to a broken pipe
#BrokenPipeException represents SIGPIPE, the signal sent to a process when it attempts to write to a pipe without a process connected to the other end.
| E4C_DECLARE_EXCEPTION | ( | BadPointerException | ) |
This exception is thrown when the process tries to dereference an invalid pointer
#BadPointerException represents SIGSEGV, the signal sent to a process when it makes an invalid memory reference, or segmentation fault.
| E4C_DECLARE_EXCEPTION | ( | NullPointerException | ) |
This exception is thrown when an unexpected null pointer is found
#NullPointerException is thrown when some part of the program gets a pointer which was expected or required to contain a valid memory address.
A null pointer exception is a special case of a bad pointer exception. The difference between them is that #NullPointerException needs to be thrown explicitly by some function, while #BadPointerException is thrown implicitly by the signal handling system (if enabled).
| E4C_DECLARE_EXCEPTION | ( | ControlSignalException | ) |
This exception is the common supertype of all control signal exceptions
Control signal exceptions are thrown when the process needs to be controlled by the user or some other process.
| E4C_DECLARE_EXCEPTION | ( | StopException | ) |
This exception is thrown to stop the process for later resumption
#StopException represents SIGSTOP, the signal sent to a process to stop it for later resumption.
SIGSTOP is usually unblock-able, it won't be handled and converted to this exception automatically on some platforms.| E4C_DECLARE_EXCEPTION | ( | KillException | ) |
This exception is thrown to terminate the process immediately
#KillException represents SIGKILL, the signal sent to a process to cause it to terminate immediately.
SIGKILL is usually unblock-able, it won't be handled and converted to this exception automatically on some platforms.| E4C_DECLARE_EXCEPTION | ( | HangUpException | ) |
This exception is thrown when the process' terminal is closed
#HangUpException represents SIGHUP, the signal sent to a process when its controlling terminal is closed.
| E4C_DECLARE_EXCEPTION | ( | TerminationException | ) |
This exception is thrown to request the termination of the process
#TerminationException represents SIGTERM, the signal sent to a process to request its termination.
| E4C_DECLARE_EXCEPTION | ( | AbortException | ) |
This exception is thrown to abort the process
#AbortException represents SIGABRT, the signal sent by computer programs to abort the process.
| E4C_DECLARE_EXCEPTION | ( | CPUTimeException | ) |
This exception is thrown when the process has used up the CPU for too long
#CPUTimeException represents SIGXCPU, the signal sent to a process when it has used up the CPU for a duration that exceeds a certain predetermined user-settable value.
| E4C_DECLARE_EXCEPTION | ( | UserControlSignalException | ) |
This exception is the common supertype of all control signal exceptions caused by the user
User control signal exceptions are thrown when the process needs to be controlled by the user.
| E4C_DECLARE_EXCEPTION | ( | UserQuitException | ) |
This exception is thrown when the user requests to quit the process
#UserQuitException represents SIGQUIT, the signal sent to a process by its controlling terminal when the user requests that the process dump core.
| E4C_DECLARE_EXCEPTION | ( | UserInterruptionException | ) |
This exception is thrown when the user requests to interrupt the process
#UserInterruptionException represents SIGINT, the signal sent to a process by its controlling terminal when a user wishes to interrupt it.
| E4C_DECLARE_EXCEPTION | ( | UserBreakException | ) |
This exception is thrown when a user wishes to break the process
#UserBreakException represents SIGBREAK, the signal sent to a process by its controlling terminal when a user wishes to break it.
| E4C_DECLARE_EXCEPTION | ( | ProgramSignalException | ) |
This exception is the common supertype of all user-defined signal exceptions
User-defined signal exceptions are thrown to indicate user-defined conditions.
| E4C_DECLARE_EXCEPTION | ( | ProgramSignal1Exception | ) |
This exception is thrown when user-defined conditions occur
#ProgramSignal1Exception represents SIGUSR1, the signal sent to a process to indicate user-defined conditions.
| E4C_DECLARE_EXCEPTION | ( | ProgramSignal2Exception | ) |
This exception is thrown when user-defined conditions occur
#ProgramSignal2Exception represents SIGUSR1, the signal sent to a process to indicate user-defined conditions.
| const e4c_exception* e4c_get_exception | ( | void | ) |
Returns the exception that was thrown
NULLThis function returns a pointer to the exception that was thrown in the surrounding exception-aware block, if any; otherwise NULL.
The function e4c_is_instance_of will determine if the thrown exception is an instance of any of the defined exception types. The type of the thrown exception can also be compared for an exact type match.
The thrown exception can be obtained any time, provided that the exception context has begun at the time of the function call. However, it is sensible to call this function only during the execution of finally or catch blocks.
Moreover, a pointer to the thrown exception obtained inside a finally or catch block must not be used outside these blocks.
The exception system objects are dinamically allocated and deallocated, as the program enters or exits try... catch... finally blocks. While it would be legal to copy the thrown exception and access to its name and message outside these blocks, care should be taken in order not to dereference the cause of the exception, unless it is a deep copy (as opposed to a shallow copy).
e4c_get_exception. Such programming error will lead to an abrupt exit of the program (or thread).| e4c_status e4c_get_status | ( | void | ) |
Returns the completeness status of the executing code block
Exception-aware code blocks have a completeness status regarding the exception handling system. This status determines whether an exception was actually thrown or not, and whether the exception was caught or not.
The status of the current block can be obtained any time, provided that the exception context has begun at the time of the function call. However, it is sensible to call this function only during the execution of finally blocks.
e4c_get_status. Such programming error will lead to an abrupt exit of the program (or thread).| E4C_BOOL e4c_is_instance_of | ( | const e4c_exception * | instance, |
| const e4c_exception_type * | exception_type | ||
| ) |
Returns whether an exception instance is of a given type
| instance | The thrown exception |
| exception_type | A previously defined type of exceptions |
e4c_is_instance_of can be used to determine if a thrown exception is an instance of a given exception type.
This function is intended to be used in a catch block, or in a finally block provided that some exception was actually thrown (i.e. e4c_get_status returs e4c_failed or e4c_recovered).
This function will return false if either instance or type are NULL.
instance must not be NULLtype must not be NULL| long e4c_library_version | ( | void | ) |
Gets the library version number
This function provides the same information as the E4C_VERSION_NUMBER macro, but the returned version number is associated with the actual, compiled library.
| void e4c_print_exception | ( | const e4c_exception * | exception | ) |
Prints a fatal error message regarding the specified exception
| exception | The uncaught exception |
This is a convenience function for showing an error message through the standard error output. It can be passed to e4c_context_set_handlers as the handler for uncaught exceptions. Will be used by default, unless otherwise set up.
In absence of NDEBUG, this function prints as much information regarding the exception as it is available, whereas in presence of NDEBUG, only the name and message of the exception are printed.
exception must not be NULL | #NullPointerException | If exception is NULL |
| void e4c_print_exception_type | ( | const e4c_exception_type * | exception_type | ) |
Prints an ASCII graph representing an exception type's hierarchy
| exception_type | An exception type |
This is a convenience function for showing an ASCII graph representing an exception type's hierarchy through the standard error output.
For example, the output for #ProgramSignal2Exception would be:
exception_type must not be NULL | #NullPointerException | If exception_type is NULL |
| const e4c_signal_mapping* const e4c_default_signal_mappings |
The array of predefined signal mappings.