As has been said, order of destructor calls is the exact reverse of order of completion of constructors (3.6.3/1
). In other words (3.8/1
), stop of lifetime of an object of static storage duration is the reverse of start of lifetime of an object of static storage duration. So it all comes down to when their constructors are called. Suppose that Printer
is a type that outputs something in its constructor in the following examples.
Namespace scope
Objects of namespace scope (global and user defined) are in any case created before the first use of any function or variable that is defined in the same translation unit that the object is defined in (3.6.2/3
). This deferred initialization (after main was called) must respect the order of definition with respect to other object definitions in the same translation unit of that objects's definition. (3.6.2/1
).
Translation unit 1:
void f() { }
extern Printer a;
Printer b("b");
Printer a("a");
extern Printer c;
Translation unit 2:
Printer c("c");
void f();
If we use f
, this will not necessarily force creation of c
, because f is not defined in the translation unit where c
was defined in. a
is created after b
because it's defined later.
Block scope
Objects of block scope (local statics) are created when control passes through their definition first or when their block is first entered for PODs (6.7/4
). Starting lifetime is tried again the next time control passes throgh it if creation couldn't successfully succeed (in case of an exception) (6.7/4
).
void g() { static Print p("P"); }
struct A {
A() {
static int n;
if(n++ == 0) throw "X";
cout << "A";
g();
}
};
void f() {
try { static A a; } catch(char const *x) { cout << x; }
}
This snippet outputs "XAP".
Class scope
For static data members, the same rule applies about order of initialization according to their definition order within the same translation unit (3.6.2/1
). This is because the rule for that is formulated as "objects defined in namespace scope..." rather than "objects of namespace scope...". In C++03 deferred initialization (delaying the construction until a variable/function is used from its translation unit) was only allowed for objects of namespace scope, which was not intended. C++0x allows this also for static data members ("non-local variable with static storage duration").
Thus by taking the above rules and taking into account that destruction order is actually determined by completion of constructors rather than by the start of them, we will get to the order ~c
~a
~b
.
If s::~s
throws an exception, C++0x says that terminate()
is called, and you end up having c
destroyed and having ended lifetime of a
without completing its destructor if it threw the exception. I can't find anything in the C++03 Standard specifying this. It seems to only specifies that for non-local statics and not also for block-scope statics like C++0x does.