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.
Related
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.
I've got a test case where I have a class with 3 subobjects (A, B and C), and the 2nd subobject B throws an exception during construction. As I understand C++, the compiler should rewind the construction of the big class and destroy the 1st object A, but not the 2nd (B) or 3rd (C) objects.
What I see is that if I use "In-class initialization" of the first object A, then instead of the first object A getting destroyed, the 3rd object C gets destroyed. Of course it is VERY BAD to destroy an object that has not been constructed! If, for example, C was a std:unique_ptr<T>, it will probably signal a segmentation violation when it tries to free a garbage pointer.
If I use old school "member initialization", then this problem doesn't happen.
I don't see this with gcc 4.8
Here's the code. The class D exposes the bug. The class E should have identical function, but it does not expose the bug.
#include <iostream>
using namespace std;
struct A {
A(const string& x) : x_(x) { cout << "A::A()" << (void*)this <<endl; }
~A() { cout << "A::~A() " << (void*)this<< endl;}
string x_;
};
struct B {
B(const A& a) { cout << "B::B()" << endl; throw "dead"; }
~B() { cout << "B::~B()" << endl;}
};
struct C {
C() { cout << "C::C()" << endl; }
~C() { cout << "C::~C()" << endl;}
};
struct D {
A a{"foo"}; // "new school In-class initialization"
B b{a};
C c;
D() { cout <<"D::D()" << endl; }
~D() { cout <<"D::~D()" << endl; }
};
struct E {
A a;
B b;
C c;
E()
:a{"foo"} // "old school member initialization"
,b(a)
{ cout <<"E::E()" << endl; }
~E() { cout <<"E::~E()" << endl; }
};
int main()
{
try {
D d;
}
catch(...)
{
cout << "got exception" << endl;
}
try {
E e;
}
catch(...)
{
cout << "got exception" << endl;
}
return 0;
}
Here is the output. I expect to see A constructed, B partially constructed then throws, then A destroyed, but that is not what I see for the D case.
$ icpc -std=c++11 test.cpp
$ ./a.out
A::A()0x7fffe0a5ee90
B::B()
C::~C()
got exception
A::A()0x7fffe0a5eea0
B::B()
A::~A() 0x7fffe0a5eea0
got exception
-- update --
The section of the standard that describes what should happen is 15.2.3
For an object of class type of any storage duration whose
initialization or destruction is terminated by an exception, the
destructor is invoked for each of the object’s fully constructed
subobjects, that is, for each subobject for which the principal
constructor (12.6.2) has completed execution and the destructor has
not yet begun execution, except that in the case of destruction, the
variant members of a union-like class are not destroyed. The
subobjects are destroyed in the reverse order of the completion of
their construction. Such destruction is sequenced before entering a
handler of the function-try-block of the constructor or destructor, if
any.
This is definitely a compiler bug, and you've answered your own question with the correct reference from the standard: [except.ctor]/3, with added emphasis:
For an object of class type of any storage duration whose initialization or destruction is terminated by an
exception, the destructor is invoked for each of the object’s fully constructed subobjects, that is, for each
subobject for which the principal constructor (12.6.2) has completed execution and the destructor has not
yet begun execution, except that in the case of destruction, the variant members of a union-like class are not
destroyed. The subobjects are destroyed in the reverse order of the completion of their construction. Such
destruction is sequenced before entering a handler of the function-try-block of the constructor or destructor,
if any.
Where:
The principal constructor is the first constructor invoked
in the construction of an object (that is, not a target constructor for that object’s construction).
C has not been fully constructed - its principal constructor has not even been called yet - so it's destructor should not be called yet.
Intel has confirmed this is an issue.
The compiler I used was
icpc (ICC) 15.0.2 20150121
You can follow the Intel forum for updates on when it is resolved.
https://software.intel.com/en-us/comment/1827356
This is a follow-up question of the post. Please see the end of this question for a definition of "function try block".
Question: If a function try block does not "handle" the exception raised in the constructor, why do we need them after all? Could you give an example taking advantage of function try block?
Considering the following code.
#include <iostream>
#include <new>
#include <exception>
using namespace std;
struct X {
int *p;
X() try : p(new int[10000000000]) {}
catch (bad_alloc &e) {
cerr << "exception caught in the constructor: " << e.what() << endl;
}
};
int main() {
try {
X x;
}
catch (exception &e){
cerr << "exception caught outside the constructor: " << e.what() << endl;
}
return 0;
}
The output is
exception caught in the constructor: std::bad_alloc
exception caught outside the constructor: std::bad_alloc
It seems to me that, no matter what I do in the function try block, the exception is always going to be thrown to the outer scope which calls the constructor, e.g. the X x; in the above code.
Definition of "function try block", excerpted from "C++ Primer 5th."
To handle an exception from a constructor initializer, we must write the constructor as a function try block. A function try block lets us associate a group of catch clauses with the initialization phase of a constructor (or the destruction phase of a destructor) as well as with the constructor’s (or destructor’s) function body.
You're right that the exception is always propagated.
The function try block enables you to catch that exception and e.g. destroy an object passed as argument (maybe this is a smart pointer class?), without introducing an artificial base class.
More generally, it gives you the ability to clean up state changes introduced by the call of the function.
For the case of a constructor:
With the exception propagation destructors are called for all successfully constructed sub-objects, including base class sub-objects (if any).
However, this not completely constructed object's own destructor is not called. The function try block is ideally not a device for doing things that would go in that destructor. The not-completely-created object's own destructor has nothing to do, for its task is to clean up state changes introduced by the constructor body and/or later member function calls, and with a common "rule of zero" design there's no such as yet.
When a constructor throws, the corresponding destructor doesn't run. That's the reason for the quote in your book : cleanup has to be done by the constructor itself.
But your example shows that the exception propagates. This is necessary since the constructor failed, and therefore no object was created. The calling code should not proceed as if the constructor created an object.
I'm trying to establish whether it is safe for a C++ function to return an object that has a constructor and a destructor. My understanding of the standard is that it ought to be possible, but my tests with simple examples show that it can be problematic. For example the following program:
#include <iostream>
using namespace std;
struct My
{ My() { cout << "My constructor " << endl; }
~My() { cout << "My destructor " << endl; }
};
My function() { My my; cout << "My function" << endl; return my; }
int main()
{ My my = function();
return 0;
}
gives the output:
My constructor
My function
My destructor
My destructor
when compiled on MSVC++, but when compiled with gcc gives the following output:
My constructor
My function
My destructor
Is this a case of "undefined behavior", or is one of the compilers not behaving in a standard way? If the latter, which ? The gcc output is closer to what I would have expected.
To date, I have been designing my classes on the assumption that for each constructor call there will be at most one destructor call, but this example seems to show that this assumption does not always hold, and can be compiler-dependent. Is there anything in the standard that specifies what should happen here, or is it better to avoid having functions return non-trivial objects ? Apologies if this question is a duplicate.
In both cases, the compiler generates a copy constructor for you, that has no output so you won't know if it is called: See this question.
In the first case the compiler generated copy constructor is used, which matches the second destructor call. The line return my; calls the copy constructor, giving it the variable my to be used to construct the return value. This doesn't generate any output.
my is then destroyed. Once the function call has completed, the return value is destroyed at the end of the line { function();.
In the second case, the copy for the return is elided completely (the compiler is allowed to do this as an optimisation). You only ever have one My instance. (Yes, it is allowed to do this even though it changes the observable behaviour of your program!)
These are both ok. Although as a general rule, if you define your own constructor and destructor, you should also define your own copy constructor (and assignment operator, and possibly move constructor and move assignment if you have c++11).
Try adding your own copy constructor and see what you get. Something like
My (const My& otherMy) { cout << "My copy constructor\n"; }
The problem is that your class My violates the Rule of Three; if you write a custom destructor then you should also write a custom copy constructor (and copy assignment operator, but that's not relevant here).
With:
struct My
{ My() { cout << "My constructor " << endl; }
My(const My &) { cout << "My copy constructor " << endl; }
~My() { cout << "My destructor " << endl; }
};
the output for MSVC is:
My constructor
My function
My copy constructor
My destructor
My destructor
As you can see, (copy) constructors match with destructors correctly.
The output under gcc is unchanged, because gcc is performing copy elision as allowed (but not required) by the standard.
You are missing two things here: the copy constructor and NRVO.
The behavior seen with MSVC++ is the "normal" behavior; my is created and the rest of the function is run; then, when returning, a copy of your object is created. The local my object is destroyed, and the copy is returned to the caller, which just discards it, resulting in its destruction.
Why does it seem that you are missing a constructor call? Because the compiler automatically generated a copy constructor, which is called but doesn't print anything. If you added your own copy constructor:
My(const My& Right) { cout << "My copy constructor " << endl; }
you'd see
My constructor <----+
My function | this is the local "my" object
My copy constructor <--|--+
My destructor <----+ | this is the return value
My destructor <-----+
So the point is: it's not that there are more calls to destructors than constructors, it's just that you are not seeing the call to the copy constructor.
In the gcc output, you are also seeing NRVO applied.
NRVO (Named Return Value Optimization) is one of the few cases where the compiler is allowed to perform an optimization that alters the visible behavior of your program. In fact, the compiler is allowed to elide the copy to the temporary return value, and construct the returned object directly, thus eliding temporary copies.
So, no copy is created, and my is actually the same object that is returned.
My constructor <-- called at the beginning of f
My function
My destructor <-- called after f is terminated, since
the caller discarded the return value of f
To date, I have been designing my classes on the assumption that for each constructor call there will be at most one destructor call [...]
You can still "assume" that since it is true. Each constructor call will go in hand with exactly one destructor call. (Remember that if you handle stuff on the free/heap memory on your own.)
[..] and can be compiler-dependent [...]
In this case it can't. It is optimization depedant. Both, MSVC and GCC behave identically if optimization is applied.
Why don't you see identical behaviour?
1. You don't track everything that happens with your object. Compiler-generated functions bypass your output.
If you want to "follow-up" on the things your compiler does with your objects, you should define all of the special members so you can really track everything and do not get bypassed by any implicit function.
struct My
{
My() { cout << "My constructor " << endl; }
My(My const&) { cout << "My copy-constructor " << endl; }
My(My &&) { cout << "My move-constructor " << endl; }
My& operator=(My const&) { cout << "My copy-assignment " << endl; }
My& operator=(My &&) { cout << "My move-assignment " << endl; }
~My() { cout << "My destructor " << endl; }
};
[Note: The move-constructor and move-assignment will not be implicitly present if you have the copy ones but it's still nice to see when the compiler use which of them.]
2. You don't compile with optimization on both MSVC and GCC.
If compiled with MSVC++11 /O2 option the output is:
My constructor
My function
My destructor
If compiled in debug mode / without optimization:
My constructor
My function
My move-constructor
My destructor
My destructor
I can't do a test on gcc to verify if there's an option that enforces all of these steps but -O0 should do the trick I guess.
What's the difference between optimized and non-optimized compilation here?
The case without any copy omittance:
The completely "non-optimized" behaviour in this line My my_in_main = function();
(changed the name to make things clear) would be:
Call function()
In function construct My My my;
Output stuff.
Copy-construct my into the return value instance.
return and destroy my instance.
Copy(or move in my example)-construct the return value instance into my_in_main.
Destroy the return value instance.
As you can see: we have at most two copies (or one copy and one move) here but the compilers may possibly omit them.
To my understanding, the first copy is omited even without optimization turned on (in this case), leaving the process as follows:
Call function()
In function construct My My my; First constructor output!
Output stuff. Function output!
Copy(or move in my example)-construct the return value instance into my_in_main. Move output!
Destroy the return value instance. Destroy output!
The my_in_main is destroy at the end of main giving the last Destroy output!. So we know what happens in the non-optimized case now.
Copy elision
The copy (or move if the class has a move constructor as in my example) can be elided.
§ 12.8 [class.copy] / 31
When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects.
So now the question is when does this happen in this example? The reason for the elison of the first copy is given in the very same paragraph:
[...] in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cvunqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value.
Return type matches type in the return statement: function will construct My my; directly into the return value.
The reason for the elison of the second copy/move:
[...] when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move.
Target type matches the type returned by the function: The return value of the function will be constructed into my_in_main.
So you have a cascade here:
My my; in your function is directly constructed into the return value which is directly constructed into my_in_main So you have in fact only one object here and function() would (whatever it does) in fact operate on the object my_in_main.
Call function()
In function construct My instance into my_in_main. Constructor output!
Output stuff. Function output!
my_in_main is still destroyed at the end of main giving a Destructor output!.
That makes three outputs in total: Those you observe if optimization is turned on.
An example where elision is not possible.
In the following example both copies mentioned above cannot be omitted because the class types do not match:
The return statement does not match the return type
The target type does not match the return type of the function
I just created two additional types:
#include <iostream>
using namespace std;
struct A
{
A(void) { cout << "A constructor " << endl; }
~A(void) { cout << "A destructor " << endl; }
};
struct B
{
B(A const&) { cout << "B copy from A" << endl; }
~B(void) { cout << "B destructor " << endl; }
};
struct C
{
C(B const &) { cout << "C copy from B" << endl; }
~C(void) { cout << "C destructor " << endl; }
};
B function() { A my; cout << "function" << endl; return my; }
int main()
{
C my_in_main(function());
return 0;
}
Here we have the "completely non-optimized behaviour" I mentioned above. I'll refer to the points I've drawn there.
A constructor (see 2.)
function (see 3.)
B copy from A (see 4.)
A destructor (see 5.)
C copy from B (see 6.)
B destructor (see 7.)
C destructor (instance in main, destroy at end of main)
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.