0

From : https://sourcemaking.com/design_patterns/to_kill_a_singleton

One thing's for sure: you can't use more than one destroyer if the singleton destructors depend on one another. An alternative is to eschew destroyers altogether and rely instead on the draft-standard atexit() function, as Tim Peierls suggested to me: I maintain that atexit() is a good way to cleanup singletons in C++ when you really want single instances with program lifetime and no replacement.

The draft standard promises a lot: The function atexit() from can be used to specify a function to be called at exit. If atexit() is to be called, the implementation shall not destroy objects initialized before an atexit() call until after the function specified in the atexit() call has been called.

The only way I can see this failing is if a statically initialized object whose destructor depends on a Singleton instance is initialized after the Singleton instance is constructed, i.e., through some other static initialization. This suggests that classes having static instances should avoid depending on singletons during destruction. (Or at least there should be a way for such classes to check for the existence of the Singleton during destruction.)

I couldn't understand the last paragraph i.e. in which case it will fail and how.

Could someone please throw some light on it.

q126y
  • 1,589
  • 4
  • 18
  • 50

1 Answers1

1

Since this uses atexit instead of destructors to clean up the Singletons, the order of object cleanup can be changed. For example:

Singleton S;
Object O;
// later in code:
Call atexit() to register cleanup function for S

Normally the destruction order for these objects will be O then S, but with the atexit call added this is reversed, so that S is cleaned up in the atexit call, then O is destroyed. If O's destructor depends in any way on the Singleton S you'll have undefined behavior while that destructor is running.

The way to avoid that is to call atexit to register the Singleton cleanup function before constructing any objects that depend on it. If O is itself a static object, this can be tricky and may require creating a class whose constructor calls atexit so it can be inserted between the two static objects.

Singleton S;
struct SAtExit {
     SAtExit() { atexit(...); }
} SCleanup;
Object O;
1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56