Ответ 1
В стандарте С++:
system_category
текущий проект С++ 17 указывает, что:
Некоторые функции в стандартных отчетах библиотеки библиотеки С++ через объект
std::error_code
(19.5.2.1). Что объектcategory()
возвращаетstd::system_category()
для ошибок, возникающих из операционной системы,или ссылку на реализациюerror_category
объект для ошибок, возникающих в другом месте. Реализация определяет возможные значения значения() для каждого из этих error > . [Пример: Для операционных систем, основанных на POSIX, реализациям рекомендуется определитьstd::system_category()
значения, идентичные значениям POSIXerrno
, с дополнительными значения, определенные в документации по операционным системам.Реализации для операционных систем, которые не основаны на POSIX рекомендуется определять значения, идентичные действующим системных значений. Для ошибок, которые не исходят из операционной системы, реализация может предоставлять перечисления для связанные значения.
Не так ясно:
-
Что должно произойти с
errno
значениями в Windows? -
является
errno
из вызова POSIX "из операционной системы" или предполагается, что он должен быть ограничен вызовами без POSIX?
generic_category
-
std::errc
- это перечисление с теми же значениями, что и код ошибки C/POSIXEFOOBAR
;Значение каждой константы
enum errc
должно совпадать с значением значение макроса<cerrno>
, показанного в приведенном выше обзоре. Независимо от того, реализует ли реализация Макросы<cerrno>
не указаны. -
make_error_code(std::errc)
генерируетerro_code
, используяgeneric_category
error_code make_error_code(errc e) noexcept;
Возвращает:
error_code(static_cast<int>(e), generic_category())
.
Это означает, что код ошибки POSIX можно использовать с generic_category
. Возможно, что значения, отличные от POSIX, могут некорректно работать с generic_catgeory
. На практике они, похоже, поддерживаются реализациями, которые я использовал.
В Boost
Сама система Boost
Документация Boost довольно короткая об этой функции:
Исходное предложение рассматривает категории ошибок как двоичный выбор между errno (то есть POSIX-стиль) и собственной операционной системой коды ошибок.
Кроме того, вы можете найти устаревшее объявление, например:
static const error_category & errno_ecat = generic_category();
В linux_error.hpp
:
Чтобы создать error_code после ошибки API:
error_code( errno, system_category() )
В windows_error.hpp
:
Чтобы создать error_code после ошибки API:
error_code( ::GetLastError(), system_category() )
В cygwin_error.hpp
:
Чтобы создать error_code после ошибки API: error_code (errno, system_category())
В Windows Boost использует system_category
для ошибок errno
:
ec = error_code( ERROR_ACCESS_DENIED, system_category() );
ec = error_code( ERROR_ALREADY_EXISTS, system_category() );
ec = error_code( ERROR_BAD_UNIT, system_category() );
ec = error_code( ERROR_WRITE_PROTECT, system_category() );
ec = error_code( WSAEWOULDBLOCK, system_category() );
В ASIO
Мы находим такой код в ASIO:
template <typename ReturnType>
inline ReturnType error_wrapper(ReturnType return_value,
boost::system::error_code& ec)
{
#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
ec = boost::system::error_code(WSAGetLastError(),
boost::asio::error::get_system_category());
#else
ec = boost::system::error_code(errno,
boost::asio::error::get_system_category());
#endif
return return_value;
}
Мы находим errno
как system_category
в коде POSIX:
int error = ::pthread_cond_init(&cond_, 0);
boost::system::error_code ec(error,
boost::asio::error::get_system_category());
Filesystem
Мы находим errno
с generic_category
в коде POSIX:
if (::chmod(p.c_str(), mode_cast(prms)))
{
if (ec == 0)
BOOST_FILESYSTEM_THROW(filesystem_error(
"boost::filesystem::permissions", p,
error_code(errno, system::generic_category())));
else
ec->assign(errno, system::generic_category());
}
В GNU libstdС++
Filesystem
Найдем errno
с generic_category
:
if (char* rp = ::realpath(pa.c_str(), buf.get())) {
[...]
}
if (errno != ENAMETOOLONG) {
ec.assign(errno, std::generic_category());
return result;
}
и не используется system_category
.
Использование libstdС++
На практике кажется, что вы можете использовать generic_category
для не-POSIX errno
с libstdС++:
std::error_code a(EADV, std::generic_category());
std::error_code b(EADV, std::system_category());
std::cerr << a.message() << '\n';
std::cerr << b.message() << '\n';
дает:
Advertise error
Advertise error
LibС++
Найдем errno
с system_category
:
int ec = pthread_join(__t_, 0);
if (ec)
throw system_error(error_code(ec, system_category()), "thread::join failed");
но не используется generic_category
.
Заключение
Я не нахожу какой-либо согласованной картины здесь, но, по-видимому:
-
вы должны использовать
system_category
при использовании Windows-ошибки в Windows; -
вы можете безопасно использовать
generic_category
для значений POSIXerrno
; -
вы не должны использовать
std::generic_category
для значений, отличных от POSIXerrno
(это может не сработать); -
Если вы не хотите проверять, является ли ваше значение
errno
POSIX одним:в системах на основе POSIX, вы должны использоватьна POSIX-системах вы можете использоватьsystem_error
сerrno
(строго говоря поддержка для этого не обязана, только поощряется).system_error
сerrno
.