Whilst developing a bigger project, I was in need of having basic error handling inside the context of a C interface.
I came up with the following solution.
// include/interface/error.h
#ifndef SDK_INTERFACE_ERROR_H
#define SDK_INTERFACE_ERROR_H
#ifdef __cplusplus
extern "C" {
#endif //__cplusplus
struct Error;
typedef struct Error Error;
typedef void(*ErrorHandler)( Error const * );
void SetExceptionHandler( ErrorHandler const * inExceptionHandler );
[[ noreturn ]] void ThrowException( Error const * inError );
#ifdef __cplusplus
}
#endif //__cplusplus
#endif //SDK_INTERFACE_ERROR_H
// source/interface/error.cpp
#include "interface/error.h"
#include <shared_mutex>
#include <mutex>
#include <cstdlib>
#include <functional>
namespace
{
std::function< void( Error const * ) > sErrorHandler = []( Error const * ){ std::abort(); };
std::shared_mutex sErrorHandlerMutex;
}
void
SetExceptionHandler( ErrorHandler const * inExceptionHandler )
{
std::unique_lock lock( sErrorHandlerMutex );
sErrorHandler = *inExceptionHandler;
}
void
ThrowException( Error const * inError )
{
std::shared_lock lock( sErrorHandlerMutex );
sErrorHandler( inError );
std::abort();
}
Errors in this context means unrecoverable errors, So error handling is simply a means to provide a user of this interface time to perform a clean exit.
However I still have the following questions
- General Code review
- Would it be safe to throw an exception inside an
ErrorHandler
, which could then be caught again outside the interface - Is it safe to pass stack addresses to
ThrowException