Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Construct std::error_code from errno on POSIX and GetLastError() on Windows

Tags:

My question: What is the correct way to construct std::error_code instances from errno values on POSIX and GetLastError() on Windows so that the instances can be compared to the well-known values from std::errc?

The longer explanation: My goal is to add an std::error_code instance to a self-made exception object that works on POSIX and Windows systems in a C++11ish way.

In my cross-platform application I'm using a self-made I/O class hierarchy that uses the POSIX fopen() and Windows' CreateFile() calls for opening/creating files. If that fails a generic, self-made open_error exception is thrown (it is derived from std::exception, yes, but it's not one of C++'s predefined exception classes). I'm trying to extend this rather bare-bones exception with an error code; to be more precise with C++11's std::error_code if I understood correctly.

My problem is how to construct such an object from errno (in the POSIX case) or GetLastError() (in the Windows case). For POSIX, as far as I've understood things, I can simply use errno in std::error_code's constructor, e.g. like this:

std::error_code ec(errno, std::generic_category()); 

And that ec should be comparable to the well-known values from std::errc.

For Windows a similar call can be made, of course:

std::error_code ec(::GetLastError(), std::generic_category()); 

But I'm not sure whether or not the values returned by GetLastError() map nicely to the well-known constants from std::errc. I've read in Boost's system library that they do for Boost's implementation of error_code, but I'm asking about the std implementation, not about Boost's.

Please don't advice to switch to using C++ streams for file access. I'd love to, but refactoring half of my code is not something I'd like to do right at this very moment.

like image 538
Moritz Bunkus Avatar asked Dec 19 '12 11:12

Moritz Bunkus


2 Answers

That's a quality of implementation issue. The const static object returned by std::system_category() is relied upon to perform the mapping from the platform-native error code enumeration to the standard std::error_condition enumeration. Under 17.6.5.14 Value of error codes [value.error.codes]:

Implementations for operating systems that are not based on POSIX are encouraged to define values identical to the operating system’s values.

You can see in http://www.boost.org/doc/libs/1_46_1/libs/system/src/error_code.cpp how Boost performs the mapping; any standard library supplied by your compiler vendor for use on Windows should do something similar.

The intended behaviour is covered in 19.5.1.5p4, describing system_category().default_error_condition(int ev):

If the argument ev corresponds to a POSIX errno value posv, the function shall return error_condition(posv, generic_category()). Otherwise, the function shall return error_condition(ev, system_category()).

So, for example, error_code(ERROR_FILE_NOT_FOUND, std::system_category()).default_error_condition() will invoke std::system_category().default_error_condition(ERROR_FILE_NOT_FOUND), which should return std::error_condition(std::no_such_file_or_directory, std::generic_category()).

like image 129
ecatmur Avatar answered Sep 17 '22 17:09

ecatmur


This is an old question, but I haven't really found a good answer on SO. The accepted answer confuses me a little as it seems to give an error_condition rather than an error_code. I have settled on the following for myself on POSIX:

std::error_code error_code_from_errno(int errno_code) {   return std::make_error_code(static_cast<std::errc>(errno_code)); } 

This always gives me the correct category (generic or system). I've had problems in the past where error codes with the same errno code compared as not equal because one had generic_category and the other had system_category.

like image 29
John Gordon Avatar answered Sep 19 '22 17:09

John Gordon