Понимание & lt; system_error & gt; средство в C ++ 11

Я пытаюсь использовать system_error средство для обработки ошибок в моей библиотеке. Я собираюсь кратко обсудить структуру библиотеки на случай, если она окажется вам полезной: пространство имен библиотеки называется commons и под этим у меня есть еще одно пространство имен dynlib, dynlib содержит классы, отвечающие за загрузку файлов .so / .dll:

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

Ошибки, которые могут возникнуть в DynLibLoader: LibraryFailedToLoad, LibraryFailedToUnload а также SymbolNotFound, Поэтому мои мысли по поводу обработки ошибок следующие: я добавлю пространство имен error под пространством имен dynlib, Затем в этом пространстве имен я определю одно перечисление для std::error_codes и одно перечисление для std::error_conditions, Из моего понимания std::error_codes должны соответствовать значению errno (Linux) или GetLastError (Win32), а std::error_conditions к таким ценностям, как LibraryFailedToLoad, SymbolNotFound и т.д. Итак, вот мои вопросы:

  • Мое понимание о std::error_code а также std::error_condition правильный?
  • Как я должен знать все возможные значения errno а также GetLastError() для того, чтобы определить их под моим std::error_codes перечисление? Что если Microsoft добавит дополнительные значения ошибок в API в будущем? Должен ли я вернуться к исходному коду и определить его в соответствии с перечислением, которое у меня есть для std::error_codes?
  • Что, если мы находимся на другой платформе, и нет способа выяснить точный код системной ошибки при возникновении ошибки?
  • Что делать, если я хочу иметь то же самое std::error_codes для всего пространства имен общего и только определить другой std::error_condition для каждого под-пространства имен, как dynlib, Это хорошая практика? Я бы сказал, да, потому что это позволит избежать дублирования кода. Но есть ли подвох за этим?
  • На данный момент я использую один std::error_category для каждого подпространства имен общего достояния. Это хорошая практика? Как вы думаете, я должен использовать std::error_category по-другому?

18

Решение

Основное различие заключается в том, что std::error_condition является портативным (независимым от платформы), в то время как std::error_code зависит от платформы. Как правило, низкоуровневый зависимый от платформы код генерирует error_codes и код клиента сравнивает эти error_codes независимым от платформы error_conditions,

19.5 [syserr] определяет длинный список стандартных (и переносимых) состояний ошибки (например, errc::no_such_file_or_directory), которые явно связаны с конкретными значениями errno (например. ENOENT). В результате вам не нужно знать полный список возможных значений errno или же GetLastError() генерируется в вашей системе. Вам нужно знать только стандартные значения, относящиеся к вашему коду. Например, ваша реализация библиотеки может выглядеть так:

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);
}

Ваш код клиента будет затем проверять, если error_code соответствует любому конкретному error_condition:

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
}

В вашем случае вы, вероятно, определите собственное перечисление ошибок (только одно перечисление) и отметите его как error_conditions включить автоматическое преобразование:

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

Затем вы можете перевести результаты различных зависящих от платформы операций в соответствующие error_condition (или же error_code Если вы предпочитаете):

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);
}
}

Ваш код клиента будет сравнивать код ошибки с возможными условиями ошибки, как указано выше:

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
}

Обратите внимание, что перечисление commons::dynlib::errc::LibraryFailedToLoad автоматически преобразуется в error_condition (используя предоставленную make_error_condition метод), потому что commons::dynlib::errc помечен is_error_condition_enum,

Отображение error_category пространство имен, вероятно, является личным предпочтением, однако это выглядит несколько искусственно. В данном конкретном случае верно, что имеет смысл иметь категорию для dynlib пространства имен, но было бы легко найти примеры, в которых было бы целесообразно иметь категории, распространяющиеся на несколько пространств имен. В некоторых случаях может быть целесообразным и практичным иметь все различные перечисления ошибок в уникальном пространстве имен (например, commons::errors).

12

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]