在 C++ 标准中:
system_category
当前的C++17 草案指出:
C++ 标准库中的某些函数通过std::error_code
(19.5.2.1) 对象报告错误。该对象的category()
成员应返回std::system_category()
源自操作系统的错误,
或返回对源自其他地方的错误的实现定义error_category
对象的引用。实现应为这些错误 > 类别中的每一个定义 value() 的可能值。[ 示例:对于基于 POSIX 的操作系统,鼓励实现将值定义std::system_category()
为与 POSIXerrno
值相同,并使用操作系统文档定义的附加值。
鼓励不基于 POSIX 的操作系统的实现定义与操作系统值相同的值。对于并非源自操作系统的错误,实现可以为相关值提供枚举。
这不是很清楚:
generic_category
这意味着 POSIX 错误代码可以与generic_category
. 非 POSIX 值可能无法与generic_catgeory
. 在实践中,它们似乎得到了我一直在使用的实现的支持。
在升压
升压系统本身
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,Boostsystem_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());
文件系统
我们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 libstdc++ 中
文件系统
我们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
.
使用 libstdc++
实际上,您似乎可以将generic_category
非 POSIXerrno
与 libstdc++ 一起使用:
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
库++
我们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
POSIX 值errno
;
你不应该能够std::generic_category
用于非POSIX vales errno
(它可能不起作用);
如果您不想检查您的errno
值是否为 POSIX 值:在基于 POSIX 的系统上,您应该能够使用system_error
(errno
严格来说,对此的支持不是强制性的,只是鼓励)。 在基于 POSIX 的系统上,您可以system_error
使用errno
.
新提案(2019-12 更新)
有人提议引入一个新的错误系统 ( std::error
, std::status_code
)。
有关设施问题的讨论,请参见相关讨论及其第 4 节<system_error>
:
- 使用 std::string
- “双 API”库的激增
- 没有任何措辞搁置 0 枚举数
- 依赖单身人士
- 没有 error_category 子类可以是文字类型
- 没有关于将额外信息附加到 error_code 的指导
- 依赖于令人惊讶的 operator== 过载
- error_category 应该正确命名为 error_domain
- 标准的 error_code-yielding 函数无论如何都会抛出异常
- 未指定的 error_code 比较语义