c++ c++11 error-handling error-code system-error

Entendiendo la facilidad<system_error> en C++ 11



c++11 error-handling (1)

La principal distinción es que std::error_condition es portátil (independiente de la plataforma) mientras que std::error_code depende de la plataforma. Normalmente, el código dependiente de la plataforma de bajo nivel genera códigos de error_codes y el código del cliente compara estos códigos de error_codes con las condiciones de error_conditions independientes de la plataforma.

19.5 [syserr] define una larga lista de condiciones de error estándar (y portátiles) (por ejemplo, errc::no_such_file_or_directory ) que están explícitamente asociadas a valores específicos de errno (por ejemplo, ENOENT ). Como resultado, no necesita conocer la lista completa de valores posibles de errno o GetLastError() generados en su sistema. Solo necesita conocer los valores estándar relevantes para su código. Por ejemplo, la implementación de su biblioteca podría verse así:

void MyLibraryClass::foo(std::error_code &ec) { // whatever platform dependent operation that might set errno // possibly with alternative platform-dependent implementations ec = make_error_code(errno); }

Su código de cliente luego verificará si el error_code coincide con alguna condición de error_condition específica:

error_code ec; myLibraryInstance.foo(ec); if (!ec) { // success } else if (errc::no_such_file_or_directory == ec) { // no_such_file_or_directory } else { // unknown or unexpected error }

En su caso, probablemente definiría su propia enumeración de errores (solo una enumeración) y la etiquetaría como error_conditions para habilitar la conversión automática:

namespace commons { namespace dynlib { enum class errc {LibraryFailedToLoad=1, LibraryFailedToUnload, SymbolNotFound}; } } namespace std { template<> struct is_error_condition_enum<commons::dynlib::errc> : true_type {}; } // TODO: implement make_error_code and make_error_condition

A continuación, podría traducir el resultado de las diversas operaciones dependientes de la plataforma en la error_condition (o error_code si lo prefiere):

void DynLibLoader::open(std::error_code &ec) { // possibly implement the windows version here as well if (NULL == dlopen(filename, flag)) { ec = make_error_code(errc::LibraryFailedToLoad); } }

Su código de cliente compararía el código de error con las posibles condiciones de error, como se indica anteriormente:

error_code ec; dynLibLoader.open(ec); if (!ec) { // success } else if (commons::dynlib::errc::LibraryFailedToLoad == ec) { // Library Failed To Load } else { // unknown or unexpected error }

Tenga en cuenta que la enumeración commons::dynlib::errc::LibraryFailedToLoad se convierte automáticamente en un error_condition (utilizando el método make_error_condition proporcionado) porque commons::dynlib::errc está etiquetado con is_error_condition_enum .

La asignación de error_category al espacio de nombres es probablemente una preferencia personal, sin embargo, parece un poco artificial. En este caso específico, es cierto que tiene sentido tener una categoría para el espacio de nombres de dynlib pero sería fácil encontrar ejemplos en los que tendría sentido tener categorías que difundan varios espacios de nombres. En algunos casos, podría ser significativo y práctico tener todas sus enumeraciones de error diferentes en un espacio de nombres único (por ejemplo, commons::errors ).

Estoy tratando de usar la instalación system_error para manejar los errores en una biblioteca mía. Voy a discutir brevemente la estructura de la biblioteca en caso de que le resulte útil: el espacio de nombres de la biblioteca se llama commons y debajo de este tengo otro espacio de nombres llamado dynlib . dynlib contiene clases que son responsables de cargar archivos .so / .dll:

namespace commons { namespace dynlib { class DynLibLoader { }; } }

Los errores que pueden producirse en DynLibLoader son LibraryFailedToLoad , LibraryFailedToUnload y SymbolNotFound . Así que mis pensamientos para manejar los errores son los siguientes: Agregaré un error espacio de nombres debajo del espacio de nombres dynlib . Luego, bajo ese espacio de nombres definiré una enumeración para std::error_codes y una enumeración para std::error_conditions . A mi entender, los std::error_codes deben corresponder al valor de errno (Linux) o GetLastError (Win32), y las condiciones std::error_conditions a valores como LibraryFailedToLoad , SymbolNotFound , etc. Entonces, aquí están mis preguntas:

  • ¿Mi entendimiento sobre std::error_code y std::error_condition correcto?
  • ¿Cómo se supone que debo conocer todos los valores posibles de errno y GetLastError() para definirlos en mi enum std::error_codes ? ¿Qué sucede si Microsoft agrega valores de error adicionales a la API en el futuro? ¿Tendré que volver al código fuente y definirlos bajo la enumeración que tengo para los códigos std::error_codes ?
  • ¿Qué sucede si estamos en otra plataforma y no hay manera de averiguar el código de error exacto del sistema cuando se produce un error?
  • ¿Qué dynlib si quiero tener los mismos std::error_codes para todo el espacio de nombres de commons y solo defino una std::error_condition diferente std::error_condition para cada sub espacio de nombres como dynlib ? ¿Es esta una buena practica? Yo diría que sí porque esto evitará el código duplicado. ¿Pero hay una trampa detrás de esto?
  • En este momento estoy usando una sola std::error_category para cada sub-espacio de nombres de commons. ¿Es esta una buena practica? ¿Crees que debería usar std::error_category diferente?