R.M. R.M. - 2 months ago 8
C++ Question

In C++, can a static object outlive its static member variable?

Regarding the order of destruction of static variables in C++, are there any guarantees about the lifetime of static objects with respect to their static member variables?

For example, if I had something like this (insanely simplified example for demonstration purposes only):

class Object {
static std::vector< Object * > all_objects;

public
Object() {
all_objects.push_back( this );
}

~Object() {
all_objects.erase(
std::remove(all_objects.begin(), all_objects.end(), this),
all_objects.end());
}
};


Would this be "safe" with respect to static Objects in different compilation units? That is, is there any guarantee that the
all_objects
member variable will stick around at least as long as any valid Object, or could there be an issue where
all_objects
is destroyed prior to the last Object instance?

And does the answer change if the code is being used as a library (say within Python) rather than as a standalone program with its own main()?

Answer

Would this be "safe" with respect to static Objects in different compilation units?

It is not safe at initialization time. There is no guarantee that all_objects will be initialized at the time a static object in a compilation unit is constructed.

I am not clear on the order of termination. My guess is that destruction happens in the reverse order of construction. If construction/initialization is not safe, destruction is likely to be unsafe too.

One way to make it safe at initialization time is wrap all_objects in a function.

class Object {
    static std::vector<Object *>& get_all_objects();

public
    Object() {
        get_all_objects().push_back( this );
    }

    ~Object() {
       std::vector<Object *>& all_objects = get_all_objects();
       all_objects.erase(
          std::remove(all_objects.begin(), all_objects.end(), this), 
          all_objects.end());
    }
};

std::vector<Object *>& Object::get_all_objects()
{
    static std::vector<Object *> all_objects;
    return all_objects;
}

This is what the C++11 Standard (3.6.3/1) has to say about destruction of objects with static storage duration.

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.

Given that, the above approach is safe for destruction. all_objects will be destructed only after the last Object will be destructed.