I've found what looks like contradictory answers regarding exceptions being thrown inside constructors in C++. One of the answers in this link says that if an exception is thrown inside a constructor, it is assumed that construction is not complete, and therefore the the destructor is not called. But this link discusses the RAII concept, using the example of a mutex created in a constructor and cleaned up in a destructor. It says that if a mutex is created in the constructor and then the constructor calls a function that throws an excpetion and no exception handler is defined, then the destructor will still be called and the mutex will be cleaned up. What
am I missing?
The destructor of the object being constructed is not executed, but all its members that were constructed are destructed; for example:
struct A {
A(int x) { ... }
~A() { ... }
};
struct B {
A a1, a2, a3;
B() : a1(1), a2(2), a3(3) { ... }
~B() { ... }
};
if when building a B instance the construction of a1 goes well, then the construction of a2 goes well but the construction of a3 throws an exception then what happens is that a2 will be destroyed (calling ~A), then a1 will be destroyed but ~B will NOT be called because the constructor didn't complete (the body didn't even start).
Even if the exception is thrown inside the ... body of B() then all of the A subobjects will be destroyed by calling ~A but still ~B will not be called.
Only if the constructor of B is completed what you get is a real B instance and then, when destroyed, ~B will be called to execute destruction code.
Let's look at this piece of code:
#include <iostream>
#include <stdexcept>
class A {
public:
A() {
std::cout << "A's constructor\n";
}
~A() {
std::cout << "A's destructor\n";
}
};
class B {
public:
B() {
std::cout << "B's constructor - begin\n";
throw std::runtime_error("Error");
std::cout << "B's constructor - end\n";
}
~B() {
std::cout << "B's destructor\n";
}
private:
A a;
};
int main() {
try {
B b;
} catch(const std::runtime_error& exc) {
std::cerr << exc.what() << '\n';
}
}
Here's the program's output:
A's constructor
B's constructor - begin
A's destructor
Error
In general, when an object is constructed first its fileds's constructors are invoked and then the constructor for the object is executed. For every successfully executed constructor there must be a destructor called. The destructors are called in reverse order. If a constructor fails then there's no destructor called but if during construction of an object some or all of its fields are constructed then they will be destroyed.
Coming back to the example, in the main function I create an object of class B. The object contains a member of class A. When the b object is created, first it's fields (in this case it's the member called a) are constructed - this is the first line of the output. Then the constructor of the b object begins execution (second line of output). The B's constructor throws an exception. Since the contructor of b's field (that is constructor of a) has already been successfully executed, a's destructor must be called - thrid line of output. Now, the b's constructor has not successfully finished its execution so the destructor is not going to be called for b. The last line of output is the effect of exception handling code in the main function.
In this example you can see that when a constructor succeeds then some time later a corresponding destructor is called. However if a constructor fails no destructor for the object will be called.
Successfully executed constructors and destructors are always paired. It's a very general rule and it's valid also for base classes (if any), objects allocated in arrays, objects allocated on stack etc. - even very weird and complicated cases are always handled this way.
Related
Can anyone explain me why the output of the below snippet is :
MyClass constructor
catch block
Why is the destructor of object m not been called as the scope of it is within try block?
When it comes to catch block with throw 0; statement, the object m of MyClass is out of scope and its destructor should have been invoked right?
Am i missing some kind of concept hear?
class MyClass {
public:
MyClass() {
std::cout << "\nMyClass constructor" ;
throw 0;
}
~MyClass() {
std::cout << "\nMyClass destructor" << std::endl;
}
};
int main(void)
{
try {
MyClass m;
} catch(int e) {
std::cout << "\ncatch block" << std::endl;
}
return 0;
}
According to
[dcl.init]/21
An object whose initialization has completed is deemed to be constructed, even if no constructor of the object’s class is invoked for the initialization.
And
[class.dtor]/12
A destructor is invoked implicitly
for a constructed object with static storage duration (6.7.1) at program termination (6.6.4),
...
When an exception is thrown from a constructor, the object's initialization is not completed, the object is not deemed constructed and no destructor is called since there is infact no object.
Why is an object's destructor not called when an exception is thrown from its constructor?
Logically: because it was never constructed, so there's nothing to destroy.
An object's lifetime only begins when the constructor completes successfully.
Practically: if you throw an exception part-way through construction, how would a destructor know which parts of the object were created (and should be destroyed), and which are just un-initialized memory? This scheme could not possibly work.
So, the destructor can't be used to "undo" a failed constructor; it's automatically handled as part of stack unwinding instead. For example, consider:
class A;
class B;
class C;
class D : public A, B {
C m_c;
D() : A(), B(), m_c() {}
};
first, storage is allocated for D. If this step is dynamic, and fails, std::bad_alloc is thrown (and the D instance never started existing)
then A::A() initializes the first (A) base-class subobject. If this fails, the subobject never started existing, the storage allocation is unwound, etc.
if A::A() succeeds, B::B() initializes the second base-class subobject. If this throws, A::~A() is automatically used to destroy the A subobject.
if both base-class subobjects succeed, C::C() is used to initialize the member object: if this throws, both the A and B base-class subobjects are destroyed in reverse order
if all the A, B and C subobjects were constructed normally, only then is the body of D::D() (the part inside the {}, after the initializer list) entered. If this throws, the C, B and A objects are destroyed (in that order: it's always reverse order of construction)
only if all those steps succeed, a new instance of D has started its lifetime. This will be destroyed with D::~D() when its lifetime ends.
UKMonkey is right. See his comment.
As you raised an exception in constructor, it could not instantiate the object m. As no object exist so no call to destructor. That is the reason we must be very careful while throwing exception from a constructor. Just comment out throw 0; and check. You will understand it.
I read the book C++ How to Program 8th Edition by Paul Deitel. There is a statement at p.645:
When an exception is thrown from the constructor for an object that's created in a new expression, the dynamically allocated memory for that object is released.
To verify this statement, I wrote code as follows:
#include <iostream>
#include <exception>
#include <memory>
class A{
public:
A(){std::cout << "A is coming." << std::endl;}
~A(){std::cout << "A is leaving." << std::endl;}
};
class B
{
public:
B()
{
std::cout << "B is coming." << std::endl;
A b;
throw 3;
}
~B(){std::cout << "B is leaving." << std::endl;}
};
int main(void)
{
try
{
std::shared_ptr<B> pi(new B);
}
catch(...)
{
std::cout << "Exception handled!" << std::endl;
}
}
The output is:
B is coming.
A is coming.
A is leaving.
Exception handled!
This shows that B's destructor isn't invoked, which seems to conflict with the statement above.
Is my code correct to verify the statement? If not, how should I modify it? If yes, does it mean that the statement is wrong?
You're confusing two things:
memory being released
the destructor being called
You've shown that the latter doesn't occur, which makes sense: how can you destroy something that wasn't properly constructed? Note that the member variables will have their destructors invoked, though, because by the time the constructor threw an exception all the member variables had been fully constructed.
But that has nothing to do with memory being released, which will assuredly occur.
[C++11: 15.2/2]: An object of any storage duration whose initialization or destruction is terminated by an exception will have destructors executed for all of its fully constructed subobjects (excluding the variant members of a union-like class), that is, for subobjects for which the principal constructor (12.6.2) has completed execution and the destructor has not yet begun execution. Similarly, if the non-delegating constructor for an object has completed execution and a delegating constructor for that object exits with an exception, the object’s destructor will be invoked. If the object was allocated in a new-expression, the matching deallocation function (3.7.4.2, 5.3.4, 12.5), if any, is called to free the storage occupied by the object.
It means that everything in the ctor of B up to the point of the exception is destruction. An instance of B itself was never constructed, therefore it must not be destructed. Note also that pi was never constructed.
std::shared_ptr<B> pi(new B) - start with new B
new B - triggers the ctor of B
std::cout ... - the output
A b; - construct an A
throw 3; - calls ~A()
- rewind, new B is "aborted"
- std::shared_ptr<B> pi(new B) is "aborted"
You could modify your code to see, that the constructor of the std::shared_ptr is never hit by replacing it with a new class of yours, taking a pointer:
struct T {
T(B*) { std::cout << "T::T()\n"; }
};
...
try
{
T pi(new B); // instead of std::shared_ptr<B> pi(new B);
}
...
The constructor of T will not be hit (cf. "pi was never constructed").
Now assume that the constructor of B would allocate memory as in:
B()
{
A* a = new A(); // in contrast to A a;
throw 3;
}
were previously A::~A() was called, that is a was deconstructed, we now have a pointer, and pointers don't need to be deconstructed. However the memory allocated and assigned to a is not deleted. (Had you used a smart pointer std::unique_ptr<A> a = std::make_unique<A>();, the memory would have been released, because the destructor of std::unique_ptr<A> is called and it will release the memory.)
I used to think that in C++, if a constructor throws an exception, the destructor of this "partially constructed" class is not called.
But it seems that it is not true anymore in C++11: I compiled the following code with g++ and it prints "X destructor" to the console. Why is this?
#include <exception>
#include <iostream>
#include <stdexcept>
using namespace std;
class X
{
public:
X() : X(10)
{
throw runtime_error("Exception thrown in X::X()");
}
X(int a)
{
cout << "X::X(" << a << ")" << endl;
}
~X()
{
cout << "X destructor" << endl;
}
};
int main()
{
try
{
X x;
}
catch(const exception& e)
{
cerr << "*** ERROR: " << e.what() << endl;
}
}
Output
Standard out:
X::X(10)
X destructor
Standard error:
*** ERROR: Exception thrown in X::X()
Delegating constuctors are indeed a new feature that introduces a new destruction logic.
Let us revisit the lifetime of an object: An object's lifetime begins when some constructor has finished. (See 15.2/2. The standard calls this the "principal constructor".) In your case, this is the constructor X(int). The second, delegating constructor X() acts as just a plain member function now. Upon scope unwinding, the destructors of all fully-constructed objects are called, and this includes x.
The implications of this are actually quite profound: You can now put "complex" work loads into a constructor and take full advantage of the usual exception propagation, as long as you make your constructor delegate to another constructor. Such a design can obviate the need for various "init"-functions that used to be popular whenever it wasn't desired to put too much work into a regular constructor.
The specific language that defines the behaviour you're seeing is:
[C++11: 15.2/2]: [..] Similarly, if the non-delegating constructor for an object
has completed execution and a delegating constructor for that object exits with an exception, the object’s destructor will be invoked. [..]
I used to think that in C++, if a constructor throws an exception, the destructor of this "partially constructed" class is not called.
But it seems that it is not true anymore in C++11
It's still true. Nothing changed since C++03 (for some value of nothing ;-) )
What you thought is still true, but there is no partially constructed object when the exception is thrown.
The C++03 TC1 standard says (emphasis mine):
An object that is partially constructed or partially destroyed will have destructors executed for all of its fully constructed subobjects, that is, for subobjects for which the constructor has completed execution and the destructor has not yet begun execution.
i.e. Any object which has completed its constructor will get destroyed by executing the destructor. That's a nice simple rule.
Fundamentally the same rule applies in C++11: as soon as X(int) has returned, the object's "constructor has completed execution" so it is fully constructed, and so its destructor will run at the appropriate time (when it goes out of scope or an exception is thrown during some later stage of its construction.) It's still the same rule, in essence.
The delegating constructor's body runs after the other constructor and can do extra work, but that doesn't change the fact the object's construction has finished, so it is completely constructed. The delegating constructor is analogous to a derived class' constructor, which executes more code after a base class' constructor finishes. In some sense you can consider your example to be like this:
class X
{
public:
X(int a)
{
cout << "X::X(" << a << ")" << endl;
}
~X()
{
cout << "X destructor" << endl;
}
};
class X_delegating : X
{
public:
X_delegating() : X(10)
{
throw runtime_error("Exception thrown in X::X()");
}
};
it's not really like this, there's only one type, but it's analogous in as much as the X(int) constructor runs, then additional code in the delegating constructor runs, and if that throws the X "base class" (which isn't really a base class) gets destroyed.
This question is inspired by Using an object after it's destructor is called
Let's consider the following code
class B
{
public:
B() { cout << "Constructor B() " << endl; }
~B() { cout << "Destructor ~B() " << endl; }
};
class A {
public:
B ob;
A()
try
{
throw 4;
}
catch(...)
{
cout << "Catch in A()\n";
}
A(int)
{
try
{
throw 4;
}
catch(...)
{
cout << "Catch in A(int)\n";
}
}
};
int main()
{
try
{
A f;
}
catch (...)
{
cout << "Catch in main()\n\n";
}
A g(1);
}
It's output is
Constructor B()
Destructor ~B()
Catch in A()
Catch in main()
Constructor B()
Catch in A(int)
Destructor ~B()
In contrast to A(int), constructor A() has the initializer list try/catch syntax. Why that makes a difference on the order of the subobject destruction? Why the exception thrown in A() propagates to main()?
Why that makes a difference on the order of the subobject destruction?
When catch in A(int) - all subobjects are alive, and you can use them. Moreover, after catch, you can continue object construction, and "return" to user properly constructed object.
When catch in A() - all subobjects, which were constructed - are destructed. And you don't know which subobjects were constructed and which not - at least with current ISO C++ syntax.
Why the exception thrown in A() propagates to main()?
Check GotW #66:
If the handler body contained the statement "throw;" then the catch block would obviously rethrow whatever exception A::A() or B::B() had emitted. What's less obvious, but clearly stated in the standard, is that if the catch block does not throw (either rethrow the original exception, or throw something new), and control reaches the end of the catch block of a constructor or destructor, then the original exception is automatically rethrown.
Think about what this means: A constructor or destructor function-try-block's handler code MUST finish by emitting some exception. There's no other way. The language doesn't care what exception it is that gets emitted -- it can be the original one, or some other translated exception -- but an exception there must be! It is impossible to keep any exceptions thrown by base or member subobject constructors from causing some exception to leak beyond their containing constructors.
In fewer words, it means that:
If construction of any base or member subobject fails, the whole object's construction must fail.
The difference is that at the end of:
A()
try
{
throw 4;
}
catch(...)
{
cout << "Catch in A()\n";
}
the exception is implicitly rethrown and no object A get constructed, whereas in:
A(int) {
try
{
throw 4;
}
catch(...)
{
cout << "Catch in A(int)\n";
}
}
you swallow the exception and an instance of A is fully constructed.
Destructors run only on fully constructed objects, that is objects whose constructor finished successfully, without throwing an exception.
EDIT: as per the destruction of subobjcets, the catch in the first case is run after the sub-object has been destructed. This is consistent with the member initialization syntax that suggests that it is what should actually happen:
A()
try : ob() // default construct
{
throw 4;
}
catch(...)
{
// here ob is already destructed
cout << "Catch in A()\n";
}
(equivalent to the first case.)
Why that makes a difference on the order of the subobject destruction?
In general, in the function catch clause of A(), you wouldn't know which members had been successfully constructed, because the exception might have come from one of their constructors. So to remove doubt they're destroyed first. Basically the function try/catch is "outside" the data member construction.
Why the exception thrown in A() propagates to main()?
The function catch clause can't make the constructor succeed (because if its members weren't constructed successfully, then the object itself hasn't been constructed successfully). So if you don't throw something else from it then the original exception is rethrown. That's just how it's defined, you can't use a function-try clause to ignore the problem. You can use a regular try/catch inside a function to ignore a problem, then it's up to you to decide whether or not the problem has prevented the object from being correctly constructed.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
What happens to base class destructor if a derived class destructor throws an exception
If I throw an exception in the constructor of a derived class, is the destructor called to clean up the base class?
The destructors of the base class(es) are then called in the reverse order.
Before that, the destructors of any already initialized member will also get called.
However, the destructor of the currently constructed derived-class won't get called, as this part of the object will not have been really constructed yet.
Yes. For example, consider:
#include <iostream>
class B
{
public:
B() { std::cout << "B()\n"; }
~B() { std::cout << "~B()\n"; }
};
class D : public B
{
public:
D() { std::cout << "D()\n"; throw 23; }
~D() { std::cout << "~D()\n"; }
};
int main()
try
{
D d;
return 0;
}
catch(...) {}
Output:
B()
D()
~B()
http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10
Every data member inside your object should clean up its own mess.
If a constructor throws an exception, the object's destructor is not
run. If your object has already done something that needs to be
undone (such as allocating some memory, opening a file, or locking
a semaphore), this "stuff that needs to be undone" must be
remembered by a data member inside the object.
Base destructors are guaranteed to be called, but not the destructor of the object itself.
Yes. Once construction of a base or member sub-object is complete, that sub-object will be properly destroyed if an exception is thrown.
Actually, throwing an exception in the constructor is one of the COMMON ways to detect object construction failure as long as it's properly handled by the caller, as there is NO return value of constructor.