Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ API design and error handling

I need to write C++ API, which consists of several exported C++ classes exposed from Dll, using .lib files (MSVC). From the answer to my another question I understand, that exported class methods cannot use exceptions, in the case if C++ API is built in one VC++ version (let's say 2010), and client code is written in another VC++ version. Since exceptions cannot be a part of public API interface, I am looking for another error handling strategy. My restrictions: I don't want to use COM, and rich error code system (like HRESULT) is not enough for me. I want to have exception-like class which contains error code, error message and any other information that I need. Also, I don't want to make separate build for every VC++ version.

My current approach is the following. Every public class method returns enumerated value (like ErrorCode). In the case the method fails, static function like GetLastErrorInfo returns the pointer to C++ class (let's say ErrorInfo), which contains reach error information. ErrorInfo is kept as thread-specific data, and contains error information from the last call in the current thread. If last API call succeeded, GetErrorInfo returns NULL.

Consider this code with exceptions:

try
{
    classPtr->DoSomething();
    cout << classPtr->GetData() << endl;
}
catch(const MyException& ex)
{
    cout << ex.GetErrorMessage() << endl;
    return;
}

Without exceptions, it looks like this:

ErrorCode result;
int data;
result = classPtr->DoSomething();
if ( result != Success )
{
    cout &lt&lt MyClass::GetLastErrorInfo()->GetErrorMessage() &lt&lt endl;
    return;
}
result = classPtr->GetData(data);
if ( result != Success )
{
    cout &lt&lt MyClass::GetLastErrorInfo()->GetErrorMessage() &lt&lt endl;
    return;
}
cout << data &lt&lt endl;

This doesn't look good. Class interface is messy: every function now has ErrorCode return type. Return values become output parameters. Is there better approach, that allows to have reach error information, and to keep clean public API interface?

like image 808
Alex F Avatar asked Dec 27 '22 07:12

Alex F


1 Answers

You are possibly overlooking a simple solution. The only restriction is that an exception cannot cross a module boundary. There is no problem with the client code itself throwing an exception. So provide an inline function in the header, say CheckReturn(), that throws the rich exception.

For inspiration, look at the COM IErrorInfo interface and its associated _com_error class. They solve the exact same problem. Also note the #import directive available in MSVC, it auto-generates the small wrapper functions that make the call and throw the exception on a failure return value. But you don't want to use COM so that's not directly usable.

like image 91
Hans Passant Avatar answered Jan 04 '23 16:01

Hans Passant