I have a class with a static non-primitive member. For example:
class SomeObject
{
... // something that will be destroyed in destructor,
// like an array pointer.
public:
SomeObject();
~SomeObject();
};
class MyClass
{
static SomeObject m_object;
public:
MyClass();
~MyClass(); // this will access m_object
static bool SetupStaticMember();
};
/// Implementation of SomeObject and MyClass ///
SomeObject MyClass::m_object;
bool dummy = MyClass::SetupStaticMember(); // Setup the values in m_object, for example,
// allocate memory that will be released in ~SomeObject().
MyClass g_my_global_class;
g_my_global_class is declared as global variable, so it's destructor is called after leaving main(). However, MyClass::m_object is static, so it will also be destroyed after main().
Is there any guarantee that ~MyClass() will execute before ~SomeObject() from MyClass::m_object? In other words, when the destructor of a global class instance is called, can I assume that the static members of this class are still there to be accessed, or does this depend on construction/destruction orders?
If the codes are written in this order, I think that g_my_global_class is constructed later, so it should be destructed first. Do things change if the line
MyClass g_my_global_class;
moves to another .cpp file and its file name causes the order to change?
First,
bool dummy = MyClass::InitStaticMember(); // m_object is initialized here
Doesn't actually intialize the static member. That happens at the line before
SomeObject MyClass::m_object;
So since you essentially have
SomeObject MyClass::m_object;
MyClass g_my_global_class;
and since objects are destroyed in the reverse order then g_my_global_class
is destroyed before MyClass::m_object
.
Now, if you move MyClass g_my_global_class;
to a different translation unit then all bets are off. The ordering is only guaranteed in a single translation unit.
Is there any guarantee that
~MyClass()
will execute before~SomeObject()
fromMyClass::m_object
?
Yes. Objects in static storage are destroyed reverse order of initialization.
Statically initialized objects such as MyClass::m_object
and g_my_global_class
are initialized in order of definition. Therefore MyClass::m_object
which is defined first, is also initialized first, and destroyed last.
Do things change if the line ... moves to another .cpp file and its file name causes the order to change?
Yes, things change. Order of definition across translation units is unspecified, so there is no guarantee about the relative initialization order (and thus no guarantee about the relative destruction order).
The typical solution to dependencies between static objects is to use the initialization on first use idiom, which is simply replacing the use of a global static with a function that returns a reference to a local static:
class MyClass
{
static SomeObject& m_object() {
static SomeObject s;
return s;
}
};
Local static objects are initialized when execution first reaches the point of declaration; hence the name of the idiom.
Any object whose own initialization calls MyClass::m_object()
, is guaranteed to be destroyed before the local static s
is destroyed and therefore can rely on its existence for their entire lifetime - including the destructor and regardless of translation unit bounds.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With