Mickey
Mickey

Reputation: 1505

C++ - catching a double exception

I have the following code:

#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;
}

Now, before stating the question, I would like to point that this code is bad practice (e.g throwing an exception from a constructor will result the object not being fully created, thus the destructor won't be called and it might cause memory leaks or other problems).

Now, The order of the main is this:

  1. Printing "Entering try...catch block".

  2. Calling A's constructor, printing "A::A()"

  3. Calling B's constructor, printing "B::B()", and throws exception.

  4. The exception was thrown, and the line "Exiting try...catch block" will not be printed. The block is exited, so A's destructor is called.

  5. A's destructor prints "A::~A()" and throws another exception.

The second exception (in 5) causes the main to throw an exception, before entering the catch block.

My question is this - is there a way to catch the second exception in the main, without altering the classes A,B?

I have tried to surround both the whole try-catch block and inside the catch block with another try-catch block but that didn't work.

Thanks.

Upvotes: 3

Views: 3029

Answers (2)

user2968720
user2968720

Reputation: 1

You may use set_terminate+longjmp in order to avoid program termination.

#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;
}

Upvotes: 0

JaMiT
JaMiT

Reputation: 16853

From cppreference.com:

As any other function, a destructor may terminate by throwing an exception [...] however if this destructor happens to be called during stack unwinding, std::terminate is called instead.

So, the attempt to throw an exception from ~A() does not result in a second exception being thrown; it results in the program being terminated. If you need to "catch" this "second exception", you would need to interfere with the termination handler. Or you could find a way to not throw an exception in the destructor. Continuing from cppreference.com:

Although std::uncaught_exception may sometimes be used to detect stack unwinding in progress, it is generally considered bad practice to allow any destructor to terminate by throwing an exception.

Upvotes: 5

Related Questions