C++ - 捕获双重异常

问题描述 投票:0回答:2

我有以下代码:

#include <iostream>
using namespace std;

class A {
public:
    A()  { cout << "A::A()" << endl;}
    ~A() { cout << "A::~A()" << endl; throw "A::exception";}
};

class B {
public:
    B()  { cout << "B::B()" << endl; throw "B::exception";}
    ~B() { cout << "B::~B()";}
};

int main() {
    try {
        cout << "Entering try...catch block" << endl;
        A   objectA;
        B   objectB;
        cout << "Exiting try...catch block" << endl;
    } catch (char const * ex) {
        cout << ex << endl;
    }
    return 0;
}

现在,在提出问题之前,我想指出这段代码是不好的做法(例如,从构造函数抛出异常将导致对象未完全创建,因此析构函数不会被调用,并且可能导致内存泄漏或其他问题)。

现在,主要的顺序是这样的:

  1. 打印

    "Entering try...catch block"

  2. 调用

    A
    的构造函数,打印
    "A::A()"

  3. 调用

    B
    的构造函数,打印
    "B::B()"
    ,并抛出异常。

  4. 抛出了异常,并且

    "Exiting try...catch block"
    行将不会被打印。该块已退出,因此调用
    A
    的析构函数。

  5. A
    的析构函数打印
    "A::~A()"
    并抛出另一个异常。

第二个异常(5 中)导致 main 在进入

catch
块之前抛出异常。

我的问题是这样的 - 有没有办法在不改变类的情况下捕获主程序中的第二个异常

A
B

我尝试用另一个

try-catch
块包围整个
catch
块和
try-catch
块内部,但这没有用。

谢谢。

c++ exception destructor constructor-exception
2个回答
5
投票

来自 cppreference.com

与任何其他函数一样,析构函数可以通过抛出异常来终止[...],但是如果在堆栈展开期间恰好调用此析构函数,则会调用

std::terminate

因此,尝试从

~A()
抛出异常不会导致抛出第二个异常;它会导致程序被终止。如果您需要“捕获”此“第二个异常”,则需要干扰终止处理程序。或者您可以找到一种不在析构函数中引发异常的方法。继续 cppreference.com:

虽然

std::uncaught_exception
有时可用于检测正在进行的堆栈展开,但通常认为允许任何析构函数通过抛出异常来终止是不好的做法。


0
投票

您可以使用set_terminate+longjmp以避免程序终止。

#include <iostream>
#include <setjmp.h>


using namespace std;

jmp_buf jmpBuf;

class A {
public:
    A()  { cout << "A::A()" << endl;}
    ~A() noexcept(false){ cout << "A::~A()" << endl; throw "A::exception";}
};

class B {
public:
    B()  { cout << "B::B()" << endl; throw "B::exception";}
    ~B() { cout << "B::~B()";}
};

int main() {

    set_terminate([](){
        cout<<"long jump begin" << endl;
        longjmp(jmpBuf,1);
    });

    if(setjmp(jmpBuf)==0) {

        try {
            cout << "Entering try...catch block" << endl;
            A objectA;
            B objectB;
            cout << "Exiting try...catch block" << endl;
        } catch (char const *ex) {
            cout << ex << endl;
        }
    }else{
        cout<<"long jump end" << endl;
    }
    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.