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的错误代码:
errnowith std::generic_category:SO answer,llvm-commits,cplusplus.comerrnowith std::system_category:SO answer,cppreference.comGetLastError()用std::generic_category:SO回答GetLastError()with std::system_category:SO回答,SO评论但是,errno并且GetLastError()不能使用相同的类别,否则一些错误代码将是不明确的.错误代码33是一个例子,因为它是EDOM和ERROR_LOCK_VIOLATION.
甚至有些地方主张WinAPI的用户制作类别,但我目前找不到任何引用.这种替代方案会特别痛苦.
哪些类别应与使用errno,并应搭配使用GetLastError(),使
std::error_code::default_error_condition()std::error_code::message()是否简单且适用于底层错误代码?
ysd*_*sdx 15
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的操作系统实现定义与操作系统值相同的值.对于不是源自操作系统的错误,实现可以提供关联值的枚举.
它不是那么清楚:
errnoWindows 上的值会发生什么?
是errno来自POSIX调用"来自操作系统"还是应该限制为非POSIX调用?
generic_categorystd::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文档对此功能非常简洁:
最初的提案将错误类别视为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中找到这种代码:
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)
我们发现,errno如system_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)
我们发现,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());
}
Run Code Online (Sandbox Code Playgroud)
我们发现errno有generic_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 ++的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)
我们发现errno有system_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系统,你预计能使用 在您可以使用的基于POSIX的系统system_error与errno(严格地说这种支持不是强制性的,只有鼓励).system_error上errno.
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>而不是您当前使用的任何错误代码映射或翻译系统.
| 归档时间: |
|
| 查看次数: |
4760 次 |
| 最近记录: |