嵌套异常

Version >= C++ 11

在异常处理期间,当你从低级函数捕获一般异常(例如文件系统错误或数据传输错误)时会出现一个常见的用例,并抛出一个更具体的高级异常,表明某些高级操作可以不执行(例如无法在 Web 上发布照片)。这允许异常处理对高级操作的特定问题做出反应,并且只允许错误消息,程序员在应用程序中找到发生异常的位置。此解决方案的缺点是异常 callstack 被截断并且原始异常丢失。这迫使开发人员手动将原始异常的文本包含到新创建的异常文本中。

嵌套异常旨在通过将描述原因的低级异常附加到高级异常来解决问题,该异常描述了在这种特定情况下它意味着什么。

由于 std::throw_with_nestedstd::nested_exception 允许嵌套异常:

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

struct MyException
{
    MyException(const std::string& message) : message(message) {}
    std::string message;
};

void print_current_exception(int level)
{
    try {
        throw;
    } catch (const std::exception& e) {
        std::cerr << std::string(level, ' ') << "exception: " << e.what() << '\n';
    } catch (const MyException& e) {
        std::cerr << std::string(level, ' ') << "MyException: " << e.message << '\n';
    } catch (...) {
        std::cerr << "Unkown exception\n";
    }
}

void print_current_exception_with_nested(int level =  0)
{
    try {
        throw;
    } catch (...) {
        print_current_exception(level);
    }    
    try {
        throw;
    } catch (const std::nested_exception& nested) {
        try {
            nested.rethrow_nested();
        } catch (...) {
            print_current_exception_with_nested(level + 1); // recursion
        }
    } catch (...) {
        //Empty // End recursion
    }
}

// sample function that catches an exception and wraps it in a nested exception
void open_file(const std::string& s)
{
    try {
        std::ifstream file(s);
        file.exceptions(std::ios_base::failbit);
    } catch(...) {
        std::throw_with_nested(MyException{"Couldn't open " + s});
    }
}
 
// sample function that catches an exception and wraps it in a nested exception
void run()
{
    try {
        open_file("nonexistent.file");
    } catch(...) {
        std::throw_with_nested( std::runtime_error("run() failed") );
    }
}
 
// runs the sample function above and prints the caught exception
int main()
{
    try {
        run();
    } catch(...) {
        print_current_exception_with_nested();
    }
}

可能的输出:

exception: run() failed
 MyException: Couldn't open nonexistent.file
  exception: basic_ios::clear

如果你只使用从 std::exception 继承的异常,则甚至可以简化代码。