This section describes the error handling strategy introduced in MGIS Version 3.1.

A function or a method using this error handling strategy is recognizable as follows:

Returned value of functions (or methods) that may fail

A function that may fail shall generally return either:

** Note **

Those returned value shall be mandatory marked with the [[nodiscard]] attribute. However, this conflicts in many case with the MGIS_EXPORT attribute. This is a defect of C++-20.

Reporting error to end-user

The Context class inherits from the ErrorBacktrace class, which has been designed to store error messages in a hierarchical way from the lowest level of the code up to the highest level function. The ErrorBacktrace is meant to be used through the Context object which is passed as the first argument to most functions.

The ErrorBacktrace class, and the Context class mostly provides the registerErrorMessage method that can register an error in the form of:

  1. a -string
  2. a -string
  3. a couple of a function allowing to return an error message from an integer value. This kind of function is provided by many HPC libraries.

For convenience, the registerErrorMessage always returns an invalid value, i.e. a value that is convertible to any of the returned type described in the previous section.

The error messages are packed up to the moment when error(s) must be reported to the end-user. The error messages can then be retrieved by the getErrorMessage method (or getRawErrorMessage, see below).

Source location

In debug mode, the source location, as returned by the std::source_location::current_location method, is automatically added to the error message returned by the getErrorMessage method.

Note that this feature is currently only supported by gcc compilers.

In some cases, the source location is not meaningful. In this case, the registerErrorMessageWithoutSourceLocation method can be used.

If the information about the source location are not wanted, the getRawErrorMessage method can be used.

Warning about usage of C-strings

Note that in the case of a C-string, the string is not copied and only the pointer is stored. The developer must then ensure that this string is not destroyed. As a rule of thumb, this string shall belong to the data section of the binary.

Warning about usage of C++-strings

C++-strings are the best way to report context sensitive error message. However, to reduce code bloat, building a complex error message shall never be implemented in a template function: one shall create a dedicated non-template function implemented in a source file.

The special case of constructors

Constructors don’t return values. There are mostly two ways to handle failure in constructors:

Here, we propose to use exceptions and to wrap constructors in dedicated functions.

The raise function

The raise function is an utility function to throw exception in a safe way: building the exception is not done in the throw statement. This is required to avoid a potential undefined behaviour if the constructor of the exception throws.

The type of the exception thrown is given by the first template argument of the raise function and defaults to std::runtime_exception.

The construct function

The construct function calls the constructor of an object that may throw an exception and returns a std::optional object that holds the object if the call to the constructor did not throw an exception.

If the constructor threw an exception, then the error message hold by the exception is registered in the instance of the ErrorBacktrace class which is passed as the first argument of the function and an empty optional object is returned.

Aside from the first argument (a reference to an instance of the ErrorBacktrace class), all the other arguments are forwarded to the constructor of the object.

Interaction with an external library that may use exceptions

The registerExceptionInErrorBacktrace function

Call to external libraries that relies on the usage of exceptions must be encapsulated in appropriate try/catch blocks as follows:

try{
  ....
} catch(...)
  registerExceptionInErrorBacktrace(e);
}

The registerExceptionInErrorBacktrace is a Lippincott-like helper function which translate exceptions derived from std::exception into error messages.

If the external library to be used, used another exception hierarchy, then appropriate versions of this helper function shall be created.