Constructors and Destructors in C++ – Part 3

We’ve talked a lot about how construction and destruction work. Now, finally, it’s time to see how they go wrong. Firstly, let’s say that an object is being constructed and an exception is thrown. In this situation the classes destructor is not called. This, in general, should not be a problem. The only exception throwing code you should have in a constructor is code that manages some resource. And, you should manage at most one resource per class. So if an exception is thrown in your constructor, it means that the resource you are managing has not been setup and so the destructor does not need to be called.

So if we have a class like this:

class Base
{
public:
	Base()
	{
		std::cout << "Base Constructor" << std::endl;
		throw std::exception();
	}

	virtual ~Base()
	{
		std::cout << "Base Destructor" << std::endl;
	}
};

and we run the following main function,

int main()
{
    try
    {
        Base baseObject;
    }
    catch(std::exception& e)
    {
        std::cout << "Exception caught" << std::endl;
    }
    return 0;
}

we will see:

Base Constructor
Exception caught

As you see, no calls to the destructor. Now suppose, with the same main function, we throw an exception from a derived class like so,

class Base
{
public:
	Base()
	{
		std::cout << "Base Constructor" << std::endl;
	}

	virtual ~Base()
	{
		std::cout << "Base Destructor" << std::endl;
	}
};

class Derived : public Base
{
public:
	Derived() : Base()
	{
		std::cout << "Derived Constructor" << std::endl;
		throw std::exception();
	}

	Derived(int i)
	{
		std::cout << "Derived with parameter Constructor" << std::endl;
	}

	virtual ~Derived()
	{
		std::cout << "Derived Destructor" << std::endl;
	}
};

Then we will see:

Base Constructor
Derived Constructor
Base Destructor
Exception caught

The Derived destructor is not called, but the Base Destructor is. This is because by the time the exception is thrown in the Derived class, we have completely the construction of the Base class, so that will need to be destroyed as normal.

Local objects that are constructed within the constructor will be destroyed as normal when an exception is thrown. So, for example code like this:

class Simple
{
public:
	Simple()
	{
		std::cout << "Simple Constructor" << std::endl;
	}

	virtual ~Simple()
	{
		std::cout << "Simple Destructor" << std::endl;
	}
};

class Basic
{
public:
	Basic()
	{
		std::cout << "Basic Constructor" << std::endl;
                Simple simpleObject;
		throw std::exception();
	}

	virtual ~Basic()
	{
		std::cout << "Basic Destructor" << std::endl;
	}
};

when executed via,

int main()
{
	try
	{
		Basic basicObject;
	}
	catch(std::exception& e)
	{
		std::cout << "Exception caught" << std::endl;
	}
	return 0;
}

will produce:

Basic Constructor
Simple Constructor
Simple Destructor
Exception caught

So, as we have seen, you can throw exceptions from the constructor. You cannot however throw an exception from a destructor. Try building the following code,

class Simple
{
public:
	Simple()
	{
		std::cout << "Simple Constructor" << std::endl;
	}

	virtual ~Simple()
	{
		std::cout << "Simple Destructor" << std::endl;
                throw std::exception();
	}
};

You should get a warn telling you that destructors are “noexcept” in C++. If you run this code as before, you will get:

Simple Constructor
Simple Destructor
terminate called after throwing an instance of 'std::exception'
  what():  std::exception
Aborted (core dumped)

C++ will always terminate when an exception like this is thrown in a destructor. The reason is simple. Suppose we throw an exception and then start unwinding the stack. If, when we destroy an object on the stack it’s destructor threw another exception, there is no way to catch both exceptions. We cannot catch one exception and abandon the other, so the program gives up and terminates whenever an exception is thrown in a destructor.

Leave a Reply

Your email address will not be published. Required fields are marked *