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.
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 valueposv
, the function shall returnerror_condition(posv, generic_category())
. Otherwise, the function shall returnerror_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())
.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With