【问题标题】:Exception handler catch(...) in C++C++ 中的异常处理程序 catch(...)
【发布时间】:2022-01-23 11:14:00
【问题描述】:

我了解 C++ 中的异常处理程序 catch(...) 可以处理任何类型的异常。我想知道如果它必须处理某种类类型的异常会发生什么 - 该类的对象是通过引用还是通过值传递给这个处理程序?

这是有助于理解这一点的代码。当在“内部尝试”中抛出类型 B 的异常时,使用 B 类的默认构造函数创建一个 B 类的未命名临时对象。当我运行这个程序时,根本不会调用 B 类的复制构造函数,而B类的这个未命名的临时对象只有在执行“Outer try 3”之后才被销毁,这意味着该对象一直向后传播到“Outer try 3”。所以我的猜测是对象是通过引用传递给 catch(...) 处理程序的,但我想看看这是否是正确的推理。

    #include <iostream>
    
    using namespace std;
    
    class A {
    public:
        A() {
            cout << "Default constructor of class A" << endl;
        }
        A(const A& a) {
            cout << "Copy constructor of class A" << endl;
        }
        A(A&& a) noexcept {
            cout << "Move constructor of class A" << endl;
        }
        ~A() {
            cout << "Destructor of class A" << endl;
        }
    };
    
    class B {
    public:
        B() {
            cout << "Default constructor of class B" << endl;
        }
        B(const B& b) {
            cout << "Copy constructor of class B" << endl;
        }
        B(B&& b) noexcept {
            cout << "Move constructor of class B" << endl;
        }
        ~B() {
            cout << "Destructor of class B" << endl;
        }
    };
    
    int main() {
        try {
            try {
                try {
                    try {
                        throw A();
                    }
                    catch (A a) {
                        cout << "Inner try" << endl;
                        throw B();
                    }
                }
                catch (...) {
                    cout << "Outer try 1" << endl;
                    throw;
                }
            }
            catch (...) {
                cout << "Outer try 2" << endl;
                throw;
            }
        }
        catch (...) {
            cout << "Outer try 3" << endl;
        }
    }

【问题讨论】:

  • hmm....我认为它根本没有传递给异常处理程序....catch(...) 在发生未捕获的异常时被调用,但它本身并没有得到异常。所以这并不意味着“它是如何通过的”,因为据我所知它并没有通过。
  • 我在我的问题中添加了代码,所以如果你能检查一下,那就太好了。
  • 这意味着对象一直向后传播到“Outer try 3” 目前尚不清楚“传播”是什么意思。该物体没有可见的痕迹。异常处理后对象被销毁,没有被复制。这就是我们所知道的(并且需要知道的)。
  • 在仔细阅读之后,我承认两件事:(1)我多次阅读标准的第 18 条,但我找不到任何提及固定到包罗万象的处理程序的参考.这样做肯定是有道理的,因为它将是通过外部处理程序推进对象最有效的方式,直到它到达需要按值复制的对象,但我找不到强制执行它的标准语言. (2) 我想要我的时间回来:-)
  • 这个论坛上有很多人,我发誓,他们的枕头下有语言标准,每天都对它低声说甜言蜜语。我会再提高一个档次,希望他们中的一个人能接受。我研究过它,并保留了很多,但是当涉及到这样的东西时,其中一些窥视者只是机器。希望其中一个可以提供更深层次的东西。祝你好运。

标签: c++ exception


【解决方案1】:

当你抛出异常时,异常对象会从throw的操作数创建。它是一个以未指定方式存储的对象。

当到达异常的匹配处理程序并且处理程序不是...时,处理程序的参数将从异常对象初始化。

本质上,如果您将catch 参数声明为非引用类型,您将在处理程序中获得异常对象(或基类子对象)的副本。这就是您在A 处理程序中看到的内容以及为什么会调用复制构造函数。副本一直存在,直到处理程序退出。如果您将参数声明为引用类型,那么您将获得对异常对象的引用,并且如果您重新抛出异常,它将始终引用同一个对象。

throw; 重新抛出实际上并没有对catch 子句的参数做任何事情。它只是导致异常处理继续搜索catch 子句并展开堆栈。异常对象还是一样的。

如果处理程序是catch(...),这不会发生任何变化。处理程序中没有要初始化的变量(引用与否),但throw; 将重新抛出并继续搜索具有相同异常对象的处理程序。

当处理程序退出而不重新抛出异常时,异常对象将被销毁。这发生在B 异常对象的最外层catch 的末尾和A 异常对象的最内层catch 的末尾。 (您会收到两个对A 的析构函数调用,一个用于catch 参数,一个用于异常对象。)

【讨论】:

    猜你喜欢
    • 2012-02-01
    • 2012-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-07
    相关资源
    最近更新 更多