古老的反模式之一是人们检查错误状态然后返回相当无用的消息,如“操作失败”而不是“操作失败,因为......”。我希望C ++文件I / O操作失败并出现异常,并获取有关失败原因的错误消息。具体来说,我希望ofstream对象在文件创建失败时引发异常并获得更多有用的消息,例如“权限被拒绝”或“无文件或路径”。
在C#或Java或Python等语言中这是微不足道的,但不知何故没有详细记录的方法来执行此C ++。默认情况下,iostream对象只是静默失败。有一些全局错误代码,但我宁愿有例外。经过大量搜索后,我读到您可以使用以下代码行启用异常:
my_file.exceptions(flog.exceptions() | std::ios::failbit | std::ifstream::badbit);
这样可行,但现在引发的异常是std::ios_base::failure
,ex.what()返回无用的字符串,如“basic_ios :: clear”。根据C ++ 11规范,std::ios_base::failure
应该是从system_error继承的,它具有.code()。message(),它将提供异常消息。让我们在这里保持这种古怪,而不是指向决定什么()不应该返回实际错误消息的人:)。问题是,即使使用C ++ 11和G ++ 4.8.4进行编译,我发现std::ios_base::failure
实际上并不是从system_error继承的。
问题
std::ios_base::failure
在最新的G ++ 4.8.4中不会从system_error继承,即使在使用C ++ 11模式进行编译时也是如此? GCC在这个领域的C ++ 11实现是不完整的还是我需要做更多的事情?以下是示例代码。你可以compile and run it here。
#include <iostream>
#include <fstream>
#include <system_error>
int main() {
try {
std::ofstream flog;
flog.exceptions(flog.exceptions() | std::ios::failbit | std::ifstream::badbit);
flog.open("~/watever/xyz.tsv", std::ios::trunc);
}
catch (const std::ios_base::failure &ex) {
std::cout << "ios_base::failure: " << ex.what();
}
catch(const std::system_error& ex) {
std::cout << "system_error: " << ex.code().message();
}
}
答案 0 :(得分:3)
根据海湾合作委员会的C++11 status documentation,完全支持“系统错误支持”。
根据Bug 57953 - no C++11 compliant std::ios_base::failure found,std::ios_base::failure
中的system_error
已更改为从C ++ 11中的ios_base.h
派生而来。如果您查看更新后的std::ios_base::failure
system_error
,则会_GLIBCXX_USE_CXX11_ABI
派生std::ios_base::failure
如果_GLIBCXX_USE_CXX11_ABI
已定义。 GCC的Revision 217559文档中提到了该定义。
然而,由于标准库的某些部分没有定义_GLIBCXX_USE_CXX11_ABI
,因此Map<Integer, List<String>> transposeMap = new HashMap<>();
map.forEach((key, list) -> list.stream().forEach(
elm -> transposeMap.put(elm,
transposeMap.get(elm) == null ? Arrays.asList(key) : (Stream.concat(transposeMap.get(elm).stream(),
Arrays.asList(key).stream()).collect(Collectors.toList())))));
的ABI问题仍然存在,但仍存在问题。
简短的回答是 - 你可能不能,至少不是GCC目前的实施方式。除非您可以使用Map<String, List<Integer>> map
定义的库重新编译库中的所有内容。
答案 1 :(得分:2)
在POSIX
系统ios
失败时设置errno
,以便您可以使用它获取有意义的错误消息。我经常这样做:
std::string getenv_as_string(std::string const& var)
{
auto ptr = std::getenv(var.c_str());
return ptr ? ptr : "";
}
// ~ doesn't work from C++
const std::string HOME = getenv_as_string("HOME");
int main()
{
try
{
std::ofstream ifs;
ifs.open(HOME + "/watever/xyz.tsv", std::ios::trunc);
if(!ifs)
throw std::runtime_error(std::strerror(errno));
// Do stuff with ifs
}
catch(std::exception const& e)
{
std::cerr << e.what() << '\n';
}
}
<强>输出:强>
No such file or directory