Re: Destruction order of local static objects
On 2011-04-08 01:34, Jens Auer wrote:
Hi,
I have some questions concerning the cleanup of local static objects
defined in multiple translation units.
The order for construction of local static objects is precisely
defined, but what about the order of destruction? Is there a defined
order for the destruction of local static objects?
Yes, it was rather precisely defined in C++03, and C++0x improved this
situation even more (and also properly honors the possibilities of
multiple threads during destruction). See below for more details.
Given the following
example, it is ensured that the static object in createA still exists
when B's destructor is called?
#include<iostream>
struct A
{
void f() {}
~A()
{
std::cout<< "A::~A()"<< std::endl;
}
};
A* createA()
{
static A a;
return&a;
}
struct B
{
~B()
{
createA->f();
I assume this was supposed to be written as
createA()->f();
instead.
std::cout<< "B::~B()"<< std::endl;
}
};
B* createB()
{
static B b( createA() );
There is no constructor part of type B that accepts an A*. I assume you
missed to add it, otherwise this initialization does not make sense to me.
return&b;
}
int main()
{
A* a = createA();
B* b = createB();
return 0;
}
The life-time of local statics is described in general as a dynamic
process, but giving the compiler freedom to move dynamic initialization
steps into the static initialization step, if some constraints are
satisfied. These constraints depend on the effects of the
initialization. There are no effects of creating an object of type A in
regard to its value, but we cannot see what the intended effects of the
B constructor would be, because you don't show it to us. It would be
better, if you provide a completely working example, because it might
depend on the details.
Without having this context information available, let me just point out
that the implementation freedom in regard to static initialization and
dynamic initialization depends on *values* of objects. There seem to be
no effect on the value of any of your types A and B during
initialization, so this indicates that an implementation is free to move
both initializations into the static initialization part.
In regard to the destructor calls we have 3.6.3 [basic.start.term] p. 1,
which says:
"If the completion of the constructor or dynamic initialization of an
object with static storage duration is sequenced before that of another,
the completion of the destructor of the second is sequenced
before the initiation of the destructor of the first. [ Note: This
definition permits concurrent destruction. ?end note ] If an object is
initialized statically, the object is destroyed in the same order as if
the object was dynamically initialized."
The question, whether the initialization is sequenced here requires a
bit of search in the wording. 3.6.2 [basic.start.init] p. 2 refers to
such ordering in regard to non-local static, but does not apply here. In
6.7 [stmt.dcl] p. 4 we find more clarification:
"An implementation is permitted to perform early initialization of other
block-scope variables with static or thread storage duration under the
same conditions that an implementation is permitted to statically
initialize a variable with static or thread storage duration in
namespace scope (3.6.2). Otherwise such a variable is initialized the
first time control passes through its declaration; such a variable is
considered initialized upon the completion of its initialization."
According to my understanding this would define a precise order in your
dynamic initialization and destruction szenario, *if* B has a
constructor taking an A. Otherwise, if both initializations are
independent, I see no wording that requires a concrete order of
destructor calls in this example.
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]