8

I have read several articles here and else where that it is OK to throw exception from constructor. However, I have noticed that it doesn't call destructor of base class or its data members if an exception is thrown from the constructor. Consider the following example:

#include <iostream>
using namespace std;
struct C
{
    C() { cout << __FUNCTION__ << endl;  }
    ~C() { cout << __FUNCTION__ << endl; }
};

struct E: public C
{
    C c;
    E() { cout << __FUNCTION__ << endl; throw 4; }
    ~E() { cout << __FUNCTION__ << endl; }
};

int main()
{
    E e;
}


$ g++ test.cpp; ./a.exe
C
C
E
terminate called after throwing an instance of 'int'
Aborted (core dumped)

In this case, E's constructor throws an exception but C's destructor as a data member or as a base class is not called. Now if C's destructor performs some cleanup operation like closing files/sockets and deleting heap allocations, this can cause problems.

So my question is why and when is it OK to throw exceptions from constructors.

user236215
  • 7,278
  • 23
  • 59
  • 87
  • Note that if you catch the exception in `main`, the destructors are invoked. See [here](http://ideone.com/nQemT). – Robᵩ Mar 10 '12 at 01:54
  • Before you get used to using exceptions, you might want to read [this](http://stackoverflow.com/questions/1744070/why-should-exceptions-be-used-conservatively) and its related question. – Shahbaz Mar 10 '12 at 02:15

4 Answers4

12

If you catch the error, the destructor will be run. When an uncaught exception is thrown in C++, the runtime calls std::terminate. By default, std::terminate calls std::abort which specifically does not call destructors on the way out.

With this version:

#include <iostream>
using namespace std;
struct C
{
    C() { cout << __FUNCTION__ << endl;  }
    ~C() { cout << __FUNCTION__ << endl; }
};

struct E: public C
{
    C c;
    E() { cout << __FUNCTION__ << endl; throw 4; }
    ~E() { cout << __FUNCTION__ << endl; }
};

int main()
{
    try {
        E e;
    } catch(...) {
    }

    return 0;
}

I get output:

C
C
E
~C
~C
Collin
  • 11,977
  • 2
  • 46
  • 60
2

I have noticed that it doesn't call destructor of base class or its data members if an exception is thrown from the constructor

Yes, it does.

However, since you don't catch that exception in the entire program, the program is immediately terminated.

If you were to catch the exception somewhere higher up the call stack, then the destructors of base class and members would be invoked as expected.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1
1) E's constructor catched the exception and ran completly.
   Therefore, its object is created and the distructor is 
   invoked.

struct C
{
    C() {cout <<__FUNCTION__<< endl;}
    ~C() {cout <<__FUNCTION__<< endl;}
};

struct E: public C
{
    C c;
    E() { 
    try {
        cout <<__FUNCTION__<< endl; 
        throw 4;
    }
    catch(int i) {
    cerr<<"int "<<i<<" is catched by "<<__FUNCTION__<<endl;
    }   
}
    ~E() {cout << __FUNCTION__ << endl;}
void print(){
    cout<<"obj of class E is created"<<endl;
}
};

int main()
{
    try {
       E e;
   e.print();
} 
catch(int i) {
   cerr<<"int "<<i<<" catched by "<<__FUNCTION__<<" function"<<endl;
    }

    return 0;
}

/*
Results:
C::C
C::C
E::E
int 4 is catched by E::E
obj of class E is created
E::~E
C::~C
C::~C
*/

2) E's constructor didn’t catch the exception and ran incompletly.
   In result, its object is not created. Therefore, its distructor
   is not invoked.

struct C
{
    C() {cout <<__FUNCTION__<< endl;}
    ~C() {cout <<__FUNCTION__<< endl;}
};

struct E: public C
{
    C c;
    E() { 
   try {
      cout <<__FUNCTION__<< endl; 
      throw 4;
   }
   catch(float i) {
      cerr<<"int "<<i<<" is catched by "<<__FUNCTION__<<endl;
   }    
}
    ~E() {cout << __FUNCTION__ << endl;}
void print(){
    cout<<"obj of class E is created"<<endl;
}
};

int main()
{
    try {
        E e;
    e.print();
} 
catch(int i) {
   cerr<<"int "<<i<<" catched by "<<__FUNCTION__<<" function"<<endl;
    }

    return 0;
}

/*
Results:
C::C
C::C
E::E
C::~C
C::~C
int 4 catched by main function
*/
Yisong Zhu
  • 11
  • 2
1

You don't handle the "exception".

> cat test.cpp
#include <iostream>

using namespace std;
struct C
{
    C() { cout << __FUNCTION__ << endl;  }
    ~C() { cout << __FUNCTION__ << endl; }
};

struct E: public C
{
    C c;
    E() { cout << __FUNCTION__ << endl; throw 4; }
    ~E() { cout << __FUNCTION__ << endl; }
};

int main()
{
    try
    {
        E e;
    }
    catch (int i)
    {
        std::cerr << "Handled " << i << std::endl;
    }
}

Build and run..

> make test
make: `test' is up to date.
> ./test
C
C
E
~C
~C
Handled 4
> 

Both Cs destructed and a perfectly normal termination.

johnsyweb
  • 136,902
  • 23
  • 188
  • 247