Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Destruction of static member in a class with global instance

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?

like image 965
Mark Avatar asked Mar 05 '18 14:03

Mark


2 Answers

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.

like image 185
NathanOliver Avatar answered Sep 24 '22 14:09

NathanOliver


Is there any guarantee that ~MyClass() will execute before ~SomeObject() from MyClass::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.

like image 42
eerorika Avatar answered Sep 25 '22 14:09

eerorika