C++

C++ : Throwing Exceptions From A Destructor

The below program shows an example of what happens when an exception gets thrown.
We notice that as soon as an exception gets thrown, the destructor of the class object(s) gets called. After the destructor gets executed, the exception gets caught.

#include<iostream>
#include<string>

using namespace std;

class Galaxy {

    private:
    string name;

    public:
    Galaxy(string arg_name) {
        name = arg_name;
        std :: cout << "Constructor of " << name << " galaxy got called." << std :: endl; 
    }   

    ~Galaxy() {
        std :: cout << "Destructor of " << name << " galaxy got called." << std :: endl;
    }

    void Form_Solar_System() {
        std :: cout << "Form solar system for " << name << " galaxy." << std :: endl; 
    }
};

int main() {
    try {
        Galaxy g1("Milky Way");
        Galaxy g2("Andromeda");
        throw 1000000;
        g1.Form_Solar_System();
        g2.Form_Solar_System();
    } catch (int e) {
        // Note the exception gets caught after stack unwinding is over.
        std :: cout << "Exception " << e << " caught" << std :: endl;
    }
    return 0;
}

Output

Constructor of Milky Way galaxy got called.
Constructor of Andromeda galaxy got called.
Destructor of Andromeda galaxy got called.
Destructor of Milky Way galaxy got called.
Exception 1000000 caught

Now consider the same program but a scenario in which an exception is thrown in the destructor (without being caught in the destructor).

  • Galaxy g1 (“Milky Way”) gets destroyed and the destructor is executed, which throws an exception.
  • Galaxy g2 (“Andromeda”) gets destroyed and the destructor is executed, which throws an exception.

When the second exception gets thrown without the first being caught, the program crashes.

Throwning exceptions from a destructor
- From C++11 onwards, the destructor defaults to ‘noexcept’. i.e The destructor will not throw.
   Writing a destructor without noexcept (false) would generate a compilation error
- If an exception still needs to be throw in the destructor make ‘noexcept’ false.
- An exception should never escape from a destructor if at all it is thrown in the destructor.
- A program would certainly crash if an exception thrown from the destructor leaves (not caught) the destructor.

C++ program to demonstrate what happens if at all an exception is thrown from a destructor

#include<iostream>
#include<string>

using namespace std;

class Galaxy {

    private:
    string name;

    public:
    Galaxy(string arg_name) {
        name = arg_name;
        std :: cout << "Constructor of " << name << " galaxy got called." << std :: endl; 
    }   
  
    ~Galaxy() noexcept(false) {
        std :: cout << "Destructor of " << name << " galaxy got called." << std :: endl; 
        throw 1000000;
    }

    void Form_Solar_System() {
        std :: cout << "Form solar system for " << name << " galaxy." << std :: endl; 
    }
};

int main() {
    try {
        Galaxy g1("Milky Way");
        Galaxy g2("Andromeda");
        g1.Form_Solar_System();
        g2.Form_Solar_System();
    } catch (int e) {
        // Note the exception gets caught after stack unwinding is over.
        std :: cout << "Exception " << e << " caught" << std :: endl;
    }
    return 0;
}

Output

Constructor of Milky Way galaxy got called.
Constructor of Andromeda galaxy got called.
Form solar system for Milky Way galaxy.
Form solar system for Andromeda galaxy.
Destructor of Andromeda galaxy got called.
Destructor of Milky Way galaxy got called.
terminate called after throwing an instance of 'int'
Aborted (core dumped)
#include<iostream>
#include<string>

using namespace std;

class Galaxy {

    private:
    string name;

    public:
    Galaxy(string arg_name) {
        name = arg_name;
        std :: cout << "Constructor of " << name << " galaxy got called." << std :: endl; 
    }   
    
    // From C++11 onwards, the destructors default to 'noexcept'
    // Writing a destructor without noexcept(false) would generate a compilation error.
    ~Galaxy() noexcept(false) {
        std :: cout << "Destructor of " << name << " galaxy got called." << std :: endl; 
        try {
            throw 1000000;
        } catch (int e) {
            std :: cout << "Exception " << e << " caught" << std :: endl;
        } catch (...) {
            std :: cout << "Some exception (don't know what :( )" << " caught" << std :: endl;
        }
    }
       
    void Form_Solar_System() {
        std :: cout << "Form solar system for " << name << " galaxy." << std :: endl; 
    }   
};

int main() {
    try {
        Galaxy g1("Milky Way");
        Galaxy g2("Andromeda");
        g1.Form_Solar_System();
        g2.Form_Solar_System();
    } catch (int e) {
        // Note the exception gets caught after stack unwinding is over.
        std :: cout << "Exception " << e << " caught" << std :: endl;
    }   
    return 0;
}

Output

Constructor of Milky Way galaxy got called.
Constructor of Andromeda galaxy got called.
Form solar system for Milky Way galaxy.
Form solar system for Andromeda galaxy.
Destructor of Andromeda galaxy got called.
Exception 1000000 caught
Destructor of Milky Way galaxy got called.
Exception 1000000 caught


Copyright (c) 2019-2021, Algotree.org.
All rights reserved.