<system_error>类别和标准/系统错误代码

moa*_*lon 26 c++ winapi posix c++11 system-error

C++ 11引入了<system_error>包含通用系统的头文件来处理错误代码.An std::error_code是一个元组,包含一个int错误代码和一个对a的引用std::error_category,它定义了错误域和错误代码的处理.标准库带有四个类别:std::generic_category,std::system_category,std::future_category,和std::iostream_category.

有冲突,在其上使用的类别,都在这里SO和C++的参考点,创建时std::error_codeS /投掷std::system_error以s errno和WinAPI的错误代码:

但是,errno并且GetLastError()不能使用相同的类别,否则一些错误代码将是不明确的.错误代码33是一个例子,因为它是EDOMERROR_LOCK_VIOLATION.

甚至有些地方主张WinAPI的用户制作类别,但我目前找不到任何引用.这种替代方案会特别痛苦.

哪些类别应与使用errno,并应搭配使用GetLastError(),使

  • std::error_code::default_error_condition()
  • std::error_code::message()

是否简单且适用于底层错误代码?

ysd*_*sdx 15

在C++标准中:

system_category

当前的C++ 17草案规定:

C++标准库中的某些函数通过std::error_code(19.5.2.1)对象报告错误.该对象的category()成员应返回std::system_category() 源自操作系统的错误, 或者error_category 对来自其他地方的错误的实现定义对象的引用.实现应为每个错误>类别定义value()的可能值.[示例:对于基于POSIX的操作系统,鼓励实现将std::system_category() 值定义为与POSIX errno值相同,并使用操作系统文档中定义的其他值. 鼓励不基于POSIX的操作系统实现定义与操作系统值相同的值.对于不是源自操作系统的错误,实现可以提供关联值的枚举.

它不是那么清楚:

  • errnoWindows 上的值会发生什么?

  • errno来自POSIX调用"来自操作系统"还是应该限制为非POSIX调用?

generic_category

  • std::errc是一个枚举,其值与C/POSIX EFOOBAR错误代码相同;

    每个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文档对此功能非常简洁:

最初的提案将错误类别视为errno(即POSIX样式)和本机操作系统的错误代码之间的二元选择.

此外,您可以找到遗留声明,例如:

static const error_category & errno_ecat = generic_category();

linux_error.hpp:

在API错误之后构造error_code: error_code( errno, system_category() )

windows_error.hpp:

在API错误之后构造error_code: error_code( ::GetLastError(), system_category() )

cygwin_error.hpp:

在API错误之后构造error_code: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() );
Run Code Online (Sandbox Code Playgroud)

在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;
}
Run Code Online (Sandbox Code Playgroud)

我们发现,errnosystem_category在POSIX代码:

int error = ::pthread_cond_init(&cond_, 0);
boost::system::error_code ec(error,
    boost::asio::error::get_system_category());
Run Code Online (Sandbox Code Playgroud)

文件系统

我们发现,errnogeneric_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());

}
Run Code Online (Sandbox Code Playgroud)

在GNU libstdc ++中

文件系统

我们发现errnogeneric_category:

if (char* rp = ::realpath(pa.c_str(), buf.get())) {
  [...]
}
if (errno != ENAMETOOLONG) {
  ec.assign(errno, std::generic_category());
  return result;
}
Run Code Online (Sandbox Code Playgroud)

并没有使用system_category.

使用libstdc ++

在实践中,似乎你可以使用libstdc ++的generic_category非POSIX errno:

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';
Run Code Online (Sandbox Code Playgroud)

得到:

Advertise error
Advertise error
Run Code Online (Sandbox Code Playgroud)

的libc ++

我们发现errnosystem_category:

int ec = pthread_join(__t_, 0);
if (ec)
  throw system_error(error_code(ec, system_category()), "thread::join failed");
Run Code Online (Sandbox Code Playgroud)

但没有使用generic_category.

结论

我在这里找不到任何一致的模式,但显然:

  • 您应该system_category在Windows上使用Windows时使用;

  • 您可以安全地使用generic_categoryPOSIX值errno;

  • 你不应该能够std::generic_category用于非POSIX vales errno(它可能不起作用);

  • 如果您不想检查您的errno值是否为POSIX:基于POSIX系统,你预计能使用system_errorerrno(严格地说这种支持不是强制性的,只有鼓励). 在您可以使用的基于POSIX的系统system_errorerrno.

  • 我们只能责怪微软定义两个不同且不相关的错误编号系统.很久以前他们真的丢球了.由于`errno`基于`#define`s,他们可以很容易地使值兼容,但没有. (3认同)
  • @rustyx,我倾向于认为真正的问题在于C++标准.拥有不同的类别是有意义的:许多库和API都有自己的错误号(OpenGL,Op​​enCL,Mach ......)但是我不太确定泛型`system_category`的价值:我们可以使用`generic_category`来实现系统特定错误的`errno`和系统特定(`windows_category`)类别. (3认同)
  • 同样如此,但显然`system_category`是来自系统的错误,因此将它与`errno`代码一起使用是很自然的,因为POSIX系统错误*是'errno`代码:*[...整数变量**errno**,由**系统调用**和一些库函数设置,如果出现错误则表明出现了问题.](http://man7.org/linux/man-pages/man3/ errno.3.html)*.要求POSIX开发人员使用`generic_category`是徒劳的,即使这会使代码变得不可移植.因此标准存在缺陷(但主要仅针对Win32). (2认同)
  • @rustyx,我不清楚什么是"系统"(以及系统是否只返回一组给定的错误代码).在Mach系统之上构建POSIX系统怎么样?你有Mach调用返回Mach错误代码和POSIX调用返回errnos. (2认同)

Nia*_*las 14

我不得不承认有关<system_error>的困惑有些意外,因为Chris在http://blog.think-async.com/2010/04/system-error-support-in-c0x-上总结了它的确切工作原理.part-1.html和我个人非常清楚地发现上面的C++标准文本.但总结一下非常简洁的话:

如果在POSIX上:

generic_category => POSIX标准errno空间

system_category=>本地POSIX errno空间(通常使用专有的errno代码扩展POSIX).使用strerror()扩展码成返回的字符串描述message().

在POSIX的实践中,两个实现在底层相同并映射本机errno空间.

如果在Windows上:

generic_category=> POSIX标准errno空间,由MSVCRT fopen()等中的各种POSIX仿真函数返回

system_category=> Win32 GetLastError()空间.使用FormatMessage()扩展码成返回的字符串描述message().

如何移植使用<system_error>

std::error_code ec;
#ifdef _WIN32
if((HANDLE)-1 == CreateFile(...))
  ec = std::error_code(GetLastError(), std::system_category());
#else
if(-1 == open(...))
  ec = std::error_code(errno, std::system_category());
#endif
// To test using portable code
if(ec == std::errc::no_such_file_or_directory)
   ...
// To convert into nearest portable error condition (lossy, may fail)
std::error_condition ec2(ec.default_error_condition())
Run Code Online (Sandbox Code Playgroud)

其他想法:

一些评论员说,<system_error>的设计很差,不应该使用.这根本不是真的,考虑到其设计时的C++ 03习惯做法,它是非常优化的,它在除Dinkumware之外的所有主要STL上生成非常紧凑的高质量固定延迟代码.它的用户可以扩展到任意错误代码系统,并标准化统一到单个系统不同的第三方库错误处理.

事实上,如果constexpr全局变量在设计时可用,它看起来会有很大的不同.也许这可能会在17之后的C++标准中得到纠正.但如果你是一个需要从中移动错误代码的程序员第三方库没有通过编写的代码丢失信息以了解这些第三方库,那么<system_error>是一个很好的解决方案.

将其视为与virtual第三方库错误代码处理的关键字类似- 它消除了传输第三方代码的代码需要理解这些代码的需要.如果您的代码库中存在该问题 - 并且大多数大型代码库都存在 - 那么绝对应该使用<system_error>而不是您当前使用的任何错误代码映射或翻译系统.

  • 这是最近在最新的 GCC 6、7 和 8 点版本中修复的错误。如果您使用的是最新版本,它将按您的预期工作。请参阅 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60555。 (2认同)

归档时间:

查看次数:

4760 次

最近记录:

8 年,1 月 前