Search code examples
c++visual-c++object-lifetime

Visual C++ runtime object destruction order


I've stumbled across a rather annoying issue relating to when the Visual C++ runtime destructs my objects as the program quits.

I have a class which is used to ensure references to certain states are valid. I need to store the states for an unknown amount of time, and during this time the state can be destroyed and I can't use shared_ptr. So I use

class MyClass
{
private:   
    static std::list<MyClass*> make_list();
    static std::list<MyClass*> refed_list;          
    static void StateClosed(B* state);

public:
    B* state;
    MyClass(B* state);
    virtual ~MyClass();

    bool still_valid() const;
 };

Each instance of MyClass adds itself to refed_list in its constructor and removes itself in its destructor. If the encapsulated state is closed, MyClass is notified and it checks refed_list for the encapsulating instance and invalidates its pointer. This isn't really relevant, the important thing is that it's using a static list and it accesses this list in the constructor/destructor. I initialize refed_list in the file where MyClass is defined.

Now, the issue.. When my program closes the runtime cleans up refed_list at some point, and after this it cleans up the instances of MyClass, calling their destructors. They then try to access refed_list which has already been cleaned up. This results in my iterators being incorrect, and I get undefined behaviour, in this case a debug assertion failure.

Is there a way around this issue? I doubt I can specify which order objects in different compilation units are destructed, but is there a way to check if refed_list is still valid? At the moment I check if refed_list.size() == 0 and it seems to work, but the behaviour of this is undefined too (I think?).


Solution

  • You can always make refed_list a pointer that is initialised on start up. That way it will never be cleaned up. (And any memory it uses will be recovered by the OS when your process exits.)

    If that sounds like a hack to work around a deeper design problem, then it probably is. :)