Consider the following code:
#include <iostream>
struct X{
X(){
throw 0;
}
};
void f(){
static X x;
}
int main(){
try {
f();
}
catch(int) {
std::cout << "Caught first time" << std::endl;
}
try {
f();
}
catch(int) {
std::cout << "Caught second time" << std::endl;
}
}
The output of this program is
Caught first time
Caught second time
So, is it guaranteed by the standard that the constructor of a static object is going to be called over and over again until it's successfully completed? I can't find the place in the standard where it is mentioned, so a quote or a reference to chapter and verse are very much welcome.
Or is there any undefined behavior involved in my example?
It is guaranteed that the construction will be attempted as long as it fails.
It's caused by what is stated in C++03 §6.7/4:
... Otherwise such an object is initialized the first time control passes through its declaration; such an object is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control re-enters the declaration (recursively) while the object is being initialized, the behavior is undefined. [Example:
int foo(int i)
{
static int s = foo(2*i); // recursive call – undefined
return i+1;
}
--end example]
I will note that gcc throws an exception in case of recursive initialization attempt, see litb's related question as for my source.
Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Can a local variable’s memory be accessed outside its scope?
Code:
#include <iostream>
using namespace std;
class B{
public:
int b;
B():b(1){}
~B(){cout << "Destructor ~B() " << endl;}
};
class A{
public:
B ob;
A()try{throw 4;}
catch(...){cout << "Catched in A() handler : ob.b= " << ob.b<<endl;}
};
int main()try{
A t;
}
catch(...){cout << "CATCHED in Main" << endl;}
Output:
Destructor ~B()
Catched in A() handler : ob.b= 1
CATCHED in Main
My Question is how it's possible to access a member variable b of an object ob that its destructor call finished.
Using a destructed object is undefined behaviour. This means that you may be getting this behaviour now, but nothing guarantees that you will get it some other time. Undefined behaviour is more dangerous than a regular bug because it can be more difficult to detect, as this example shows.
UPDATE: Following some comments, I'll explain why OP's code produces that output.
try function blocks are a somewhat obscure feature in C++. You can surround the whole body of a function inside a try block, with its corresponding catch. This is, instead of:
void foo()
{
try
{
//...
}
catch (/*whatever*/)
{
//...
}
}
You can write:
void foo()
try
{
//...
}
catch (/*whatever*/)
{
//...
}
This is not too useful, really, but can be marginally useful for constructors, because this is the only way to include the initialisation list inside the try block. Thus, OP's code for the A constructor is equivalent to:
A()
try
: b()
{
throw 4;
}
catch(...)
{
cout << "Catched in A() handler : ob.b= " << ob.b<<endl;
}
I said this is just marginally useful because you cannot use the object you are constructing inside the catch block; if you throw inside the try block, the exception will leave the constructor body, so the object will have never been constructed and any constructed data member will be immediately destructed before entering the catch block. But it might have some use for logging purposes.
Now, as we all know, a constructor (asuming we are not using the nothrow version) can only do two things:
Return a constructed object
Throw an exception
In this constructor we throw, but the exception is caught in the catch block. So what happens now? What will be returned to the code calling the constructor? We cannot return a constructed object because we have none, so there is only one alternative: the catch block must throw. And this is actually what the standard mandates in this case. If we do not throw explicitly, the compiler will silently add a throw; instruction at the end of the catch block. So, elaborating a bit more, the constructor is equivalent to the following:
A()
try
: b()
{
throw 4;
}
catch(...)
{
cout << "Catched in A() handler : ob.b= " << ob.b<<endl;
throw;
}
And this is the reason why the exception is caught twice: once in A constructor and once in main().
Because while the object has been destroyed, the actual memory that it occupied still exists. However, it's undefined behavior, and may or may not work.
That might be a bug in your compiler.
When I ran your code, the destructor is called in the proper order. The output is:
Catched in A() handler : ob.b= 1
Destructor ~B()
And I can't imagine any reason why catch in main is executed. The exception was already caught in A::A().
Update
I was confused by the edit. Originally, it was initializer list try/catch syntax which makes a difference. Now I can reproduce OP's output and it is UB indeed. I got a crash.
class IA
{
public:
virtual void Print() = 0;
}
IA* GetA();
class A : public IA
{
public:
int num = 10;
A()
{
GetA()->Print();
}
void Print()
{
std::cout << num << std::endl;
}
}
IA* GetA()
{
static A a;
return &a;
}
int main()
{
GetA();
std::cout << "End" << std::endl;
getchar();
return 0;
}
Obviously, class A's constructor function calls itself.
"static A a" will get stuck in a loop.
On VS2013, this code can get out from the loop and print "End" on the console.
On VS2017, this code gets stuck in a loop.
**What does VS2013 do for this code?
Nothing in particular has to happen. According to the C++ standard:
[stmt.dcl] (emphasis mine)
4 Dynamic initialization of a block-scope variable with static storage
duration or thread storage duration is performed the first time
control passes through its declaration; such a variable is considered
initialized upon the completion of its initialization. If the
initialization exits by throwing an exception, the initialization is
not complete, so it will be tried again the next time control enters
the declaration. If control enters the declaration concurrently while
the variable is being initialized, the concurrent execution shall wait
for completion of the initialization. If control re-enters the
declaration recursively while the variable is being initialized, the
behavior is undefined. [ Example:
int foo(int i) {
static int s = foo(2*i); // recursive call - undefined
return i+1;
}
— end example ]
The statement I emboldened is exactly what happens in your program. It's also what the standard's example shows as undefined. The language specification says an implementation can do whatever it deems appropriate. So it could cause an infinite loop, or it may not, depending on the synchronization primitives your implementation uses to prevent concurrent reentry into the block (the initialization has to be thread safe).
Even before C++11, the behavior of recursive reentry was undefined. An implementation could do anything to make sure an object is initialized only once, which in turn could produce different results.
But you can't expect anything specific to happen portably. Not to mention undefined behavior always leaves room for a small chance of nasal demons.
The behaviour is undefined. The reason it "worked" in Visual Studio 2013 is that it didn't implement thread safe initialisation of function statics. What is probably happening is that the first call to GetA() creates a and calls the constructor. The second call to GetA() then just returns the partially constructed a. As the body of your constructor doesn't initialise anything calling Print() doesn't crash.
Visual Studio 2017 does implement thread safe initialisation. and presumably locks some mutex on entry to GetA() if a is not initialised, the second call to GetA() then encounters the locked mutex and deadlocks.
Note in both cases this is just my guess from the observed behaviour, the actual behaviour is undefined, for example GetA() may end up creating 2 instances of A.
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.
I decided to do a test with computed gotos and local statics
void g() { std::cout << "init "; }
void f() {
int z = 0;
y: z++;
static int x =
(g(), z == 1 ? ({ goto *&&y; 0; }) : 0);
}
int main() { f(); std::cout << "!"; f(); }
I wanted to see whether the output would be "init init !". But to my surprise I didn't get that output, but instead GCC handled it gracefully, outputting at runtime:
init terminated by recursive_init_error: exception
What's that exception? Is it a Standard exception? C++03 or C++0x? Thanks for any explanation.
It's caused by what is stated in C++03 §6.7/4:
... Otherwise such an object is initialized the first time control passes through its declaration; such an object is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control re-enters the declaration (recursively) while the object is being initialized, the behavior is undefined. [Example:
int foo(int i)
{
static int s = foo(2*i); // recursive call – undefined
return i+1;
}
--end example]
GCC throws an exception in that case. Here's some documentation about it.
C++11 update: The following wording was added in C++11, just before the text about the recursive case:
If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.88
88 The implementation must not introduce any deadlock around execution of the initializer.
Doesn't change the problem here, but does make this construct thread-safe when there is no recursion.
In this question of mine, #DeadMG says that reinitializing a class through the this pointer is undefined behaviour. Is there any mentioning thereof in the standard somewhere?
Example:
#include <iostream>
class X{
int _i;
public:
X() : _i(0) { std::cout << "X()\n"; }
X(int i) : _i(i) { std::cout << "X(int)\n"; }
~X(){ std::cout << "~X()\n"; }
void foo(){
this->~X();
new (this) X(5);
}
void print_i(){
std::cout << _i << "\n";
}
};
int main(){
X x;
x.foo();
// mock random stack noise
int noise[20];
x.print_i();
}
Example output at Ideone (I know that UB can also be "seemingly correct behaviour").
Note that I did not call the destructor outside of the class, as to not access an object whose lifetime has ended. Also note, that #DeadMG says that directly calling the destructor is okay as-long-as it's called once for every constructor.
That would be okay if it didn't conflict with stack unwinding.
You destroy the object, then reconstruct it via the pointer. That's what you would do if you needed to construct and destroy an array of objects that don't have a default constructor.
The problem is this is exception unsafe. What if calling the constructor throws an exception and stack is unwound and the destructor is called for the second time?
{
X x;
x.foo(); // here ~X succeeds, then construction fails
} //then the destructor is invoked for the second time.
That aspect specifically would be undefined behavior.
Apart from #sharptooth's answer. I am just wondering for 2 more cases. At least they are worth mentioning.
(1) If the foo() was invoked using a pointer on heap which was allocated using malloc(). The constructor is not called. Can it be safe ?
(2) What if the derived class is calling foo(). Will it be a good behavior ? e.g.
struct Y : X {}; // especially when there is virtual ~X()
int main ()
{
Y y;
y.foo();
}