What Happens If a Constructor Throws an Exception

What happens if a constructor throws an exception?

No, throwing an exception is the best way to signal an error during object construction. (Since there's no return value, there's no other way, other than constructing a headless object, which is bad style in C++.)

From the man himself, Bjarne Stroustrup: http://www.stroustrup.com/bs_faq2.html#ctor-exceptions

(If you are working in a project where exceptions aren't allowed, then you have to make the constructor infallible, and move any logic that could fail into a factory function that has the possibility of returning an error.)

Re: "But my destructor was not called"

Indeed.
In C++ the lifetime of an object is said to begin when the constructor runs to completion. And it ends right when the destructor is called. If the ctor throws, then the dtor is not called.

(But dtors of any member variable objects, whose ctors already ran to completion before this ctor ran, are called.)

You should consult the standard, or a good textbook for more details, esp. related to what happens when inheritance is involved. As a general rule of thumb, destructors are called in the reverse order of construction.

Your question about why "~B" was not called in your specific code, it's because you do not catch the exception in main. If you change your code so that main catches the exception, then "~B()" will be called. But, when an exception is thrown which has no catch, the implementation is free to terminate the program without calling destructors or destroying statically initialized objects.

Reference in C++11 standard (emphasis mine):

15.5.1 The std::terminate() function [except.terminate]

1
In some situations exception handling must be abandoned for less subtle error handling techniques.

...

2
In such cases, std::terminate() is called (18.8.3). In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called.

As a side note, generally speaking with gcc and clang, ~B will be called anyways in your example program, while with MSVC, ~B will not be called. Exception handling is complex and the standard allows that compiler writers can experiment with and choose what implementation that they think is best in this regard, but they cannot choose to give undefined behavior.

If it's really important for your program that the destructors are called even in this case, then you should make sure to catch exceptions in main so that your code will be portable (work the same on all conforming compilers). For example:

int main() {
try {
A a;
} catch (...) {}
}

This way, compilers like MSVC will be obligated to call the destructor of B before exiting.

When is it right for a constructor to throw an exception?

The constructor's job is to bring the object into a usable state. There are basically two schools of thought on this.

One group favors two-stage construction. The constructor merely brings the object into a sleeper state in which it refuses to do any work. There's an additional function that does the actual initialization.

I've never understood the reasoning behind this approach. I'm firmly in the group that supports one-stage construction, where the object is fully initialized and usable after construction.

One-stage constructors should throw if they fail to fully initialize the object. If the object cannot be initialized, it must not be allowed to exist, so the constructor must throw.

What destructors are run when the constructor throws an exception?

if a constructor throws an exception, what destructors are run?

Destructors of all the objects completely created in that scope.

Does it make any difference if the exception is during the initialization list or the body?

All completed objects will be destructed.

If constructor was never completely called object was never constructed and hence cannot be destructed.

what about inheritance and members? Presumably all completed constructions get destructed. If only some members are constructed, do only those get destructed? If there is multiple inheritance, do all completed constructors get destructed? Does virtual inheritance change anything?

All completed constructions do get destructed. Yes, only the completely created objects get destructed.

Good Read:

Constructor Failures by Herb Sutter

Especially, love the part where he explains:

In biological terms, conception took place -- the constructor began --, but despite best efforts it was followed by a miscarriage -- the constructor never ran to term(ination).

Incidentally, this is why a destructor will never be called if the constructor didn't succeed -- there's nothing to destroy. "It cannot die, for it never lived." Note that this makes the phrase "an object whose constructor threw an exception" really an oxymoron. Such a thing is even less than an ex-object... it never lived, never was, never breathed its first.

Throwing exceptions from constructors

Yes, throwing an exception from the failed constructor is the standard way of doing this. Read this FAQ about Handling a constructor that fails for more information. Having a init() method will also work, but everybody who creates the object of mutex has to remember that init() has to be called. I feel it goes against the RAII principle.

Throwing an exception through a constructor

Let me start with an scenario of failing object construction that can exemplify what could go wrong if you could use such failed object:

Let's define a class A, such that:

class A {
private String a = "A";

public A() throws Exception {
throw new Exception();
}
}

Now, let's assume we would like to create an object of type A in a try...catch block.

A a = null;
try{
a = new A();
}catch(Exception e) {
//...
}
System.out.println(a);

Evidently, the output of this code will be: null.

Why Java does not return a partially constructed version of A? After all, by the point the constructor fails its name field member has already being initialized, right?

Java does not do that because the object was not successfully built. The object is in a inconsistent state, and it is therefore discarded by Java. Your variable A is not even initialized, it is kept as null.

Now, as you know, to fully build a new object, all its super classes must be initialized first. If one of the super classes failed to build, what would be the final state of the object? It is impossible to determine that.

Look at this more elaborate example

class A {
private final int a;
public A() throws Exception {
a = 10;
}
}

class B extends A {
private final int b;
public B() throws Exception {
methodThatThrowsException();
b = 20;
}
}

class C extends B {
public C() throws Exception { super(); }
}

When the constructor of C is invoked, if an exception occurs on initializing B, what would be the value of the final variable int b?

As such, the object C cannot be created, it is bogus, it is trash, it is not fully initialized.

How to delete object if constructor throws an exception?

To assess the exception safety, you need to provide more detail of the construction of the object in GameBase::getGame.

The rule is through, that if a constructor throws, the object is not created, hence the destructor is not called. Associated memory allocations are also deallocated (i.e. the memory for the object itself).

The issue then becomes, how was the memory allocated to begin with? If it was with a new GameBase(...), then there is no need to deallocate or delete the resultant pointer - the memory is deallocated by the runtime.


For clarity on what happens to the member variables that are already constructed; they are destructed on the exception of the "parent" object. Consider the sample code;

#include <iostream>
using namespace std;
struct M {
M() { cout << "M ctor" << endl; }
~M() { cout << "M dtor" << endl; }
};
struct C {
M m_;
C() { cout << "C ctor" << endl; throw exception(); }
~C() { cout << "C dtor" << endl; }
};
auto main() -> int {
try {
C c;
}
catch (exception& e) {
cout << e.what() << endl;
}
}

The output is;

M ctor
C ctor
M dtor
std::exception

If the M m_ member is to be dynamically allocated, favour a unique_ptr or a shared_ptr over a naked pointer, and allow the smart pointers to manage the object for you; as follows;

#include <iostream>
#include <memory>
using namespace std;
struct M {
M() { cout << "M ctor" << endl; }
~M() { cout << "M dtor" << endl; }
};
struct C {
unique_ptr<M> m_;
C() : m_(new M()) { cout << "C ctor" << endl; throw exception(); }
~C() { cout << "C dtor" << endl; }
};

The output here mirrors the output above.

Destroying the member variables of an object when an exception is thrown in its constructor in C++

The destructor of AnimalLoverProfile is never called because this object is not constructed yet, while the destructor for theName will be called because this object is properly constructed (even though it is a field of an object that has not been completely constructed yet). It is possible to avoid any memory leaks here by using smart pointers:

::std::unique_ptr<Image> profilePicture;
::std::unique_ptr<Image> pictureOfPet;

In this case, when new Image(pictureOfPetFileName) throws, the profilePicture object will have already been constructed, which means that its destructor will be called, just as the destructor of theName is called.

Can constructors throw exceptions in Java?

Yes, constructors can throw exceptions. Usually this means that the new object is immediately eligible for garbage collection (although it may not be collected for some time, of course). It's possible for the "half-constructed" object to stick around though, if it's made itself visible earlier in the constructor (e.g. by assigning a static field, or adding itself to a collection).

One thing to be careful of about throwing exceptions in the constructor: because the caller (usually) will have no way of using the new object, the constructor ought to be careful to avoid acquiring unmanaged resources (file handles etc) and then throwing an exception without releasing them. For example, if the constructor tries to open a FileInputStream and a FileOutputStream, and the first succeeds but the second fails, you should try to close the first stream. This becomes harder if it's a subclass constructor which throws the exception, of course... it all becomes a bit tricky. It's not a problem very often, but it's worth considering.

Exception thrown in a constructor: is the destructor called?

The destructor will not be called because the foo object is not considered fully constructed until a constructor has finished executing (note that this means if you throw in a constructor that delegated to a different constructor then the destructor will be called). Throwing from a constructor is not undefined behaviour.



Related Topics



Leave a reply



Submit