Reputation: 254
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
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