问题
As far as I've understood, one of the best practices to check system_error
conditions in a portable manner is to compare their code()
value with values in the std::errc
enumeration. However, when I try to run the following code, this does not seem to work.
#include <cassert>
#include <cerrno>
#include <system_error>
int main() {
try {
throw std::system_error(ENOENT, std::system_category());
} catch (std::system_error const & e) {
assert(e.code() == std::errc::no_such_file_or_directory); // <- FAILS!?
}
}
Do I misunderstand how these diagnostic errors are supposed to work, or am I doing something wrong? How should one compare std::system_error
exceptions to std::errc
values?
EDIT: The code seems to work properly using clang++
and libc++, but fails when building against libstdc++ regardless of which GCC or Clang compiler (and version) I use. Related to PR 60555? Any portable workaround?
回答1:
You're not doing anything wrong. As confirmed in comments by T.C. and in recent similar questions, this is indeed caused by PR #60555. Fortunately, this bug was already fixed in their VCS by August 8, 2018:
Fixed on all active branches, so will be fixed in the 6.5, 7.4, 8.3 and 9.1 releases.
There seems to be no good workaround for this, so it is now just a matter of GCC developers releasing new versions of GCC and a matter of years until these get incorporated into popular distributions until we can finally start using this nice modern feature of C++11. But that's life...
回答2:
e.code()
returns an instance of ::std::error_code
which has overloaded operator ==
which leads to implicit construction of error_condition
object as right hand expression out of std::errc::no_such_file_or_directory
. Comparison will fail because error_code returned by exception has system_category
while another one will have generic_category
. You should compare with error_code::value()
instead. Note that this comparison requires static_cast
of std::errc
value because it is an enum class
and does not get implicitly converted to int. Working example:
#include <cassert>
#include <cerrno>
#include <system_error>
#include <iostream>
int main()
{
::std::cout << static_cast< int >(ENOENT) << ::std::endl;
::std::cout << static_cast< int >(::std::errc::no_such_file_or_directory) << ::std::endl;
try
{
throw std::system_error(ENOENT, std::system_category());
}
catch(::std::system_error const & e)
{
assert(e.code().value() == static_cast< int >(::std::errc::no_such_file_or_directory));
}
}
来源:https://stackoverflow.com/questions/44405394/how-to-portably-compare-stdsystem-error-exceptions-to-stderrc-values