Reporting system errors in C++ made easy

Reporting system errors in C++ is a daunting task. By system errors I mean errors returned by standard C library functions, POSIX or Windows API. In an ideal world you’d have a nice C++ API with errors reported as exceptions. But often you need to use this nasty C function that indicates failure by a special return value and sets errno. Or even worse, you have to call a Windows API function and the error code returned by GetLastError needs to be converted to a readable form via FormatMessage that will only appeal to you if you like functions with 7 arguments with meaning of some of them depending on values of the other.

To cope with this, the C++ Format library now provides two exception classes, SystemError and WindowsError. The constructors of both classes take an error code, a format string and arbitrary formatting arguments like the format function. Each constructor formats the arguments according to the format string, gets the error message corresponding to the error code and constructs an exception object with the description of the form:

<your-message>: <system-error-message>

where <your-message> is your formatted message and <system-error-message> is the system error message.

It is best illustrated with an example. Let’s say we need to open a file and pass the FILE object into some legacy C API. That’s how you can do this with proper error handling using SystemError:

FILE *f = fopen(filename, "r");
if (!f)
  throw fmt::SystemError(errno, "Cannot open file '{}'", filename);

If the file doens’t exist, this will throw SystemError exception with a description such as “Cannot open file ‘test.log’: No such file or directory”. And of course you can wrap this in a nice reusable RAII class that makes sure the file is closed when the object is destroyed.

The second class, WindowsError is similar, but it accept error codes as given by GetLastError on Windows. Obviously this class is only available on Windows.

This functionality is available in C++ Format version 0.10.0 and later. Unlike std::system_error and friends, it works with legacy compilers that don’t (fully) support C++11.

Update: brought the post up to date with the latest C++ Format API.