chrisaverage
chrisaverage

Reputation: 254

Static object with access to static member in the destructor

I'm trying to implement the following behavior (simplified):

Conceptually something like this:

class Object {
public:
//...

~Object() { reg.erase(this);  }
static void register(Object* obj) { reg.insert(obj); }

static std::set<Object*> reg;
}

This is simplified, as it's not really a set but a more complicated container. As a result there are some iterators etc. involved in the register() and the destructor. I also omitted getters/setters and access control for brevity.

The problem I have with this is that it works as long as no one creates a static Object (or derived). It will then depend on the actual order of destruction of the static set and the static object (which is undefined if I'm not mistaken). I tested that it really crashes or not, depending on the order of these two. I can't(and don't want to) guarantee that no static instance of Object will be created. I also don't want to enforce user of the class to call any cleanup code etc. Object should be "self aware".

I tried to employ singleton for the set but I keep circling back to the same chicken and egg problem with statics in the destructor.

How can I either fix this or achieve the same behavior with another design (possibly without so much statics)? Maybe there's a way to ensure that a particular static will be destroyed after anything else (at least in "my" code)?

Upvotes: 3

Views: 126

Answers (1)

eerorika
eerorika

Reputation: 238361

Would it be acceptable for you to enforce the user of the class to use Construct On First Use Idiom for all static instances of Object? Then, they should always be constructed after the container which should be constructed before main. Static objects are destructed in reverse order of construction. Therefore all static Object that are constructed after the container will be destroyed first.

Quote from standard §3.6.3 / 1:

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

If that's not acceptable, how about adding a flag to the Object class:

class Object {
public:
    bool registered; // init to false, set to true on registration
    ~Object() { if(registered) reg.erase(this);  }

Then modify the destructor of the container (use a custom delegating container or subclass if you cannot modify the current container) to set the flag false for each pointed object before clearing contents. This may also be possible if you wrap the container into a unique_ptr with a custom deleter.

Upvotes: 1

Related Questions