c++ - 捕获 C++ 文件 IO 期间所有错误(或 ios 对象中的任何错误)的最佳实践

标签 c++ c++11 iostream

在 C++ 中捕获文件 IO 期间所有错误的最佳实践是什么?更具体地说,处理 ios 对象可能出现的错误的最佳做法是什么?例如,下面的程序从磁盘读取一个文件并打印它:

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <exception>
#include <stdexcept>

// Defines a custom exception
struct MyException : public std::exception {
    std::string s;
    MyException(std::string s_) : s(s_) {};
    const char * what () const throw () {
        return ("MyException: " + s).c_str();
    }
};

// Prints out nested exceptions
void print_exception(std::exception const & e, size_t const level =  0) {
    std::cerr << std::string(level, ' ') << "exception: " << e.what() << '\n';
    try {
        std::rethrow_if_nested(e);
    } catch(const std::exception& e) {
        print_exception(e, level+1);
    } catch(...) {}
}

// Read the specified filename into a string
std::string read_into_string(std::string const & fname) {
    // Create the file stream 
    std::ifstream fin;
    fin.exceptions(std::ifstream::failbit | std::ifstream::badbit);

    // Open the file
    try {
        fin.open(fname.c_str());
    } catch(...) {
        std::throw_with_nested(MyException(
            "Unable to open the file: " + fname));
    }

    // Make sure to close out the file if there's a problem
    try {
        // Create the string stream
        std::stringstream sin;
        sin.exceptions(std::ifstream::failbit | std::ifstream::badbit);

        // Put the file stream into a string stream
        try {
            sin << fin.rdbuf();
        } catch(...) {
            std::throw_with_nested(MyException(
                "Error when pusing the file stream into the string stream"));
        }

        // Turn the string stream into a string
        std::string str;
        try {
            str = sin.str();
        } catch(...) {
            std::throw_with_nested(MyException(
                "Error converting the string stream into a string")); 
        }        

        // Close out the file
        fin.close();

        // Return the string;
        return str;

    } catch(...) {
        // Close out the file
        fin.close();

        // Rethrow the exception
        throw;
    }
}

int main() {
    try {
        std::string str(read_into_string("file.txt"));
        std::cout << str;
    } catch(const std::exception& e) {
        print_exception(e);
    }
}

但是,它看起来非常非常重。基本上,似乎我们每次触摸 ios 对象时都必须检查,因为可能会出现问题,这有助于准确了解错误的位置。此外,上面的代码包含多个文件关闭,一个是一切正常,另一个是异常,这是不可取的。最后,我没有检查其他 ios 对象(如 cout)的错误状态,但从技术上讲,因为它们是 ios 对象,它们不能设置一个应该被捕获的错误或失败位吗?如果出现错误,是否需要关闭字符串流?

实际上,核心问题是:处理 ios 对象可能出现的错误的最佳做法是什么?

最佳答案

在 C++ 中的 I/O 流上启用 .exceptions() 并不是常见的做法。很可能你学过其他语言,他们教你尽可能使用异常。 不要

毫无异常(exception)地处理流上的错误非常容易:流将从真实变为虚假。此外,除非您重置失败位,否则对虚假流的任何操作都将完全无效。

此外,还有一种将整个输入流转储到输出流的方法。

// Read the specified filename into a string
std::string read_into_string(std::string const & fname) {
    // Create the file stream 
    std::ifstream fin(fname.c_str());
    std::ostringstream oss;
    oss << fin.rdbuf();

    if (!fin) throw MyException();

    return oss.str();
}

但是,您可能需要重新考虑在单个流中输入的需求。通常我发现一系列的行更有用。

关于c++ - 捕获 C++ 文件 IO 期间所有错误(或 ios 对象中的任何错误)的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26223489/

相关文章:

c++ - 基于 SFINAE 的特征来确定是否支持运算符 +

c++ - 如何解决 Eclipse CDT 中 C++ 文件中的 "Unresolved inclusion: <iostream>"?

c++ - 如何在 C++/Windows 中输出到控制台

c# - 如何将 C# 元组公开给 C++

c++ - 为什么 constexpr 不能只是默认值?

c++ - 哪些稳定的 c++11 特性可以安全使用

c++ - Lambda 捕获与参数 - 有性能差异吗?

c++ - 该对象具有与成员函数 C++ 不兼容的类型限定符

c++ - MPI_Comm_spawn 和 MPI_Reduce

c++ - 有人在为 C++ 开发高级标准库吗