C++ 如何在C+;中创建文件时获取IO错误消息+;?

C++ 如何在C+;中创建文件时获取IO错误消息+;?,c++,c++11,exception,exception-handling,io,C++,C++11,Exception,Exception Handling,Io,一种古老的反模式是人们检查错误状态,然后返回相当无用的消息,如“操作失败”,而不是“操作失败,因为…”。我希望C++文件I/O操作失败,并获取错误消息。具体来说,我希望流对象在文件创建失败时引发异常,并获得更有用的消息,如“权限被拒绝”或“无文件或路径” 这是微不足道的,比如C++语言,java语言或者Python语言,但是不知怎么的,没有足够的文档化的方法来完成C++。默认情况下,iostream对象只是无声地失败。有一些全局错误代码,但我宁愿有例外。经过大量搜索,我了解到您可以使用以下代码行

一种古老的反模式是人们检查错误状态,然后返回相当无用的消息,如“操作失败”,而不是“操作失败,因为…”。我希望C++文件I/O操作失败,并获取错误消息。具体来说,我希望流对象在文件创建失败时引发异常,并获得更有用的消息,如“权限被拒绝”或“无文件或路径”

<>这是微不足道的,比如C++语言,java语言或者Python语言,但是不知怎么的,没有足够的文档化的方法来完成C++。默认情况下,iostream对象只是无声地失败。有一些全局错误代码,但我宁愿有例外。经过大量搜索,我了解到您可以使用以下代码行启用异常:

my_file.exceptions(flog.exceptions() | std::ios::failbit | std::ifstream::badbit);
这是可行的,但现在引发的异常是
std::ios\u base::failure
,而ex.what()返回无用的字符串,如“basic\u ios::clear”。根据C++11规范,
std::ios_base::failure
应该是从system_error继承的,该system_error具有.code().message(),将给出异常消息。让我们暂且不谈这一奇怪现象,不要把矛头指向决定()不应返回实际错误消息的人:)。问题是,即使在使用C++11和G++4.8.4进行编译时,我发现
std::ios\u base::failure
实际上并不是从系统错误继承的

问题

  • 为什么即使在使用C++11模式编译时,
    std::ios_base::failure
    也不会从最新的G++4.8.4中的系统错误中继承?GCC对C++11的实现在这方面是不完整的,还是我需要做更多的工作
  • 当IO操作在C++中失败并获得错误消息时,我如何达到提高异常的目的?即使在最新的C++11或C++14中,也没有办法做到这一点吗?有哪些替代方案 下面是示例代码。你可以

    #包括
    #包括
    #包括
    int main(){
    试一试{
    标准:流絮;
    flog.exceptions(flog.exceptions()| std::ios::failbit | std::ifstream::badbit);
    flog.open(“~/watever/xyz.tsv”,std::ios::trunc);
    }
    捕获(const std::ios_base::failure&ex){
    标准::cout
    
  • 根据GCC,完全支持“系统错误支持”

    根据,在C++11中,
    std::ios_base::failure
    被更改为派生自
    system_error
    。如果查看更新的
    ios_base.h
    std::ios_base::failure
    则派生自
    system_error
    如果
    \u GLIBCXX\u USE\u cx11\u ABI
    被定义。该定义在GCC的文档中提到激动

    但是,由于标准库的某些部分没有定义
    \u GLIBCXX\u使用\u CXX11\u ABI
    ,因此仍然存在关于
    std::ios\u base::failure
    的ABI问题的回归:

  • 简而言之,您可能不能,至少在GCC当前的实现中不能。除非您可以使用定义的
    \u GLIBCXX\u USE\u cx11\u ABI
    重新编译库中的所有内容


  • POSIX
    systems
    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';
        }
    }
    

    必须通过谷歌查找,但感谢您是否可以改为抛出ios_base::failure异常并使用fail()方法:
    if(flog.fail())抛出std::ios_base::failure(std::strerror(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