📜  C ++ |异常处理问题6(1)

📅  最后修改于: 2023-12-03 15:13:45.033000             🧑  作者: Mango

C++ 异常处理问题6

本篇将介绍在 C++ 中处理异常时可能遇到的一些问题。

问题描述

在 C++ 中,当抛出一个异常时,异常的对象会在程序的调用栈中被查找对应的 catch 块。但是,如果在查找的过程中遇到了一个全局变量的析构函数抛出了异常,那么这个异常就会导致程序异常终止,而不是被 catch 块捕获处理。

例如,考虑下面的程序:

#include <iostream>

struct Exception {
    Exception() { std::cout << "Exception constructed\n"; }
    ~Exception() { std::cout << "Exception destroyed\n"; throw "Exception in destructor"; }
};

Exception ex;

int main() {
    try {
        throw 42;
    }
    catch (int i) {
        std::cout << "Caught " << i << std::endl;
    }
}

该程序抛出了一个 int 类型的异常,但是在进行 catch 块查找时,全局变量 ex 的析构函数抛出了一个字符串类型的异常,导致程序异常终止,输出为:

Exception constructed
terminate called after throwing an instance of 'char const*'
Aborted (core dumped)

可以看到,由于析构函数抛出了异常,导致程序没有被正确地结束,而是抛出了一个 char const* 类型的异常,最终导致程序异常终止。

解决方案

为了避免全局变量的析构函数抛出在程序的异常处理过程中导致意外的终止,我们需要对析构函数进行特殊的处理。具体来说,可以在析构函数中使用标准函数 std::uncaught_exception 来判断当前程序是否正在进行异常处理。如果是,我们就应该吞下任何在析构函数中抛出的异常;如果不是,则正常地抛出异常。

例如,我们可以将上面的代码修改如下:

#include <iostream>

struct Exception {
    Exception() { std::cout << "Exception constructed\n"; }
    ~Exception() {
        std::cout << "Exception destroyed\n";
        if (std::uncaught_exception()) {
            std::cout << "Swallowing exception in destructor\n";
        }
        else {
            throw "Exception in destructor";
        }
    }
};

Exception ex;

int main() {
    try {
        throw 42;
    }
    catch (int i) {
        std::cout << "Caught " << i << std::endl;
    }
}

该程序的输出为:

Exception constructed
Caught 42
Exception destroyed

可以看到,由于我们在析构函数中使用了 std::uncaught_exception 函数,所以即使 ex 的析构函数抛出了一个字符串类型的异常,也不会导致程序异常终止,而是被正确地处理掉了。

总结

在 C++ 中处理异常时,需要注意全局变量的析构函数可能会在程序的异常处理过程中抛出异常,导致程序意外的终止。为了避免这种情况,我们应该在析构函数中使用 std::uncaught_exception 函数来判断当前程序是否正在进行异常处理,并根据情况来处理在析构函数中抛出的异常。