简体   繁体   中英

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?).

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. :)

I don't think this is true:

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.

The runtime will certainly clean up the list, but not the objects in the list because they're pointers. The only way to do that is to use a smart pointer class like shared_ptr. Still, if you did that, the objects would be trying to access the list while it is being destroyed, which i'm not sure is undefined behavior but it certainly seems shaky.

Perhaps you should redesign it so that the objects don't need to reference the list where they're stored, or at least to do it before the list is destroyed (and by that I mean before list::~list is even called).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM