Construya std :: error_code desde errno en POSIX y GetLastError () en Windows

Mi pregunta: ¿Cuál es la forma correcta de construir instancias std::error_code partir de valores errno en POSIX y GetLastError() en Windows para que las instancias se puedan comparar con los valores conocidos de std::errc ?

La explicación más larga: mi objective es agregar una instancia std::error_code a un objeto de excepción hecho por sí mismo que funciona en sistemas POSIX y Windows de una manera C ++.

En mi aplicación multiplataforma, estoy usando una jerarquía de clase de E / S de creación propia que usa POSIX fopen() y las llamadas a Windows CreateFile() para abrir / crear archivos. Si eso falla, se open_error excepción genérica, open_error hecha por open_error misma (se deriva de std::exception , sí, pero no es una de las clases de excepción predefinidas de C ++). Estoy tratando de extender esta excepción bastante simple con un código de error; para ser más precisos con el std::error_code C ++ 11 si entendí correctamente.

Mi problema es cómo construir un objeto de este tipo desde errno (en el caso de POSIX) o GetLastError() (en el caso de Windows). Para POSIX, por lo que he entendido, puedo usar errno en el constructor de std::error_code , por ejemplo:

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

Y esa ec debe ser comparable a los valores conocidos de std::errc .

Para Windows se puede hacer una llamada similar, por supuesto:

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

Pero no estoy seguro de si los valores devueltos por GetLastError() corresponden bien con las constantes conocidas de std::errc . He leído en la biblioteca del sistema de Boost que hacen para la implementación de Boost de error_code , pero estoy preguntando sobre la implementación std , no sobre la de Boost.

Por favor, no aconseje cambiar al uso de flujos de C ++ para acceder a archivos. Me encantaría, pero refactorizar la mitad de mi código no es algo que me gustaría hacer en este preciso momento.

Eso es un problema de calidad de implementación. Se confía en el objeto estático const devuelto por std::system_category() para realizar el mapeo de la enumeración de código de error nativo de la plataforma a la enumeración estándar std::error_condition . En 17.6.5.14, el valor de los códigos de error [value.error.codes] :

Se recomienda que las implementaciones para sistemas operativos que no se basan en POSIX definan valores idénticos a los valores del sistema operativo.

Puede ver en http://www.boost.org/doc/libs/1_46_1/libs/system/src/error_code.cpp cómo Boost realiza el mapeo; cualquier biblioteca estándar suministrada por su proveedor del comstackdor para su uso en Windows debería hacer algo similar.

El comportamiento deseado está cubierto en 19.5.1.5p4, describiendo system_category().default_error_condition(int ev) :

Si el argumento ev corresponde a un posv valor errno de POSIX, la función devolverá error_condition(posv, generic_category()) . De lo contrario, la función devolverá error_condition(ev, system_category()) .

Así, por ejemplo, error_code(ERROR_FILE_NOT_FOUND, std::system_category()).default_error_condition() invocará std::system_category().default_error_condition(ERROR_FILE_NOT_FOUND) std::error_condition(std::no_such_file_or_directory, std::generic_category()) .

Esta es una pregunta antigua, pero realmente no he encontrado una buena respuesta en SO. La respuesta aceptada me confunde un poco, ya que parece dar un error_condition lugar de un error_code . Me he decidido por lo siguiente en POSIX:

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

Esto siempre me da la categoría correcta (genérico o sistema). He tenido problemas en el pasado donde los códigos de error con el mismo código errno se compararon con no iguales porque uno tenía una categoría generic_category y la otra una categoría de sistema.