Jump to content


c++ static destructor sequence


7 replies to this topic

#1 ElOmmy

    New Member

  • Members
  • Pip
  • 7 posts

Posted 09 February 2006 - 03:07 PM

Hi
i've just come across a really unpleasant problem - static destructors.
what i want is to call an "exit" function after "everything". this means, after all calls to static destructors.
i've tried the atexit C runtime library function, which adds a function pointer to a LIFO exit routine stack, but apparently MS VC++ (2005, havent tried other versions yet) uses the same 'atexit' exit routine stack to push a compiler generated function that calls static destructors - and this routine appears to be added somewhere during CRT initialization, assuring it definitely gets called after my custom exit routine.
any ideas?

#2 Alex

    Valued Member

  • Members
  • PipPipPip
  • 152 posts

Posted 09 February 2006 - 03:34 PM

you can force a clean up of all static destructors via _cexit().
The function returns after it has finished (unlike the other incarnations of exit which terminate your app).

ALex

#3 pater

    Valued Member

  • Members
  • PipPipPip
  • 117 posts

Posted 09 February 2006 - 04:51 PM

What I do to circumvent this problem is that I have a base class for all classes that need static destruction (and also static construction).


enum {

  I4_INIT_TYPE_MEMORY_MANAGER,     // main i4 memory manager

  I4_INIT_TYPE_PRIORITY,		   // Anything that only relies on memman.

  I4_INIT_TYPE_THREADS,            // initialized thread info


  I4_INIT_TYPE_STRING_MANAGER,

  I4_INIT_TYPE_FILE_MANAGER,

  I4_INIT_TYPE_DLLS,

  I4_INIT_TYPE_BEFORE_OTHER,

  I4_INIT_TYPE_OTHER,

  I4_INIT_TYPE_AFTER_ALL			//For anything that relies upon others

};

class i4_init_class

{

public:

  static i4_init_class *first_init; 

  i4_init_class *next_init;


  virtual int init_type() { return I4_INIT_TYPE_OTHER; }


  virtual void init()   {}

  virtual void uninit() {}


  i4_init_class();

  virtual ~i4_init_class();

};

(the init_type is just an enumeration of initialisation priorities)
Derived classes override the init() or uninit() method (or both), but contain no code (except variable initialisations) in their constructor. The actual code (like memory allocation/deallocation) has been moved to init()/uninit()
CPP file:


void i4_init()

{

  I4_ASSERT(!i4_inited, "i4 already initialized");

  //This is one of the few places where code is not time-critical

  


  for (int t=0; t<=I4_INIT_TYPE_AFTER_ALL; t++)

  {

    i4_init_class *i=i4_init_class::first_init;  

	Current_Init_Class=0;

    for (;i;i=i->next_init)

		{

		if (t==I4_INIT_TYPE_MEMORY_MANAGER)

			{

			Num_Init_Classes++;

			}

		Current_Init_Class++;

		if (i->init_type()==t)//sucht alle init-Typen ab und initialisiert den Richtigen (Reihenfolge)

			i->init();

		}


    if (t==I4_INIT_TYPE_MEMORY_MANAGER)

      i4_inited=i4_T;   // ok to allocate memory after this stage

  }

  i4_warning("Successfully initialized %d system components.",Num_Init_Classes);


}


void i4_uninit()

{

  I4_ASSERT(i4_inited, "i4_uninit() without i4_init()");


  for (int t=I4_INIT_TYPE_AFTER_ALL; t>=0; t--)

  {

    i4_init_class *i=i4_init_class::first_init;  

    for (;i;i=i->next_init)

      if (i->init_type()==t)

        i->uninit();

  }


  i4_inited=i4_F;

}



i4_init_class::~i4_init_class()

{

  i4_init_class *last=0, *i=first_init;


  for (;i && i!=this;)

  {

    last=i;

    i=i->next_init;

  }

  

  if (!i)

    i4_error("couldn't find init to remove");


  if (last)

    last->next_init=next_init;

  else

    first_init=next_init;


  next_init=0;

}




i4_init_class::i4_init_class()

{

  this->next_init=first_init;

  first_init=this;

}

At the beginning of the prg, i call the static i4_init() function, at the end, I call i4_uninit.
This ensures all classes get initialized/deinitialized in a specific order. Since I use a lot more singletons than init_types, some of them still get called in a random order, but I can make sure that they don't depend on each other. As an example, I don't care in which order my INIT_TYPE_DLLS-type classes get called, but I care that they're called after the memory manager is initialized.
Destruction happens in reverse order, of course.

#4 monjardin

    Senior Member

  • Members
  • PipPipPipPip
  • 1033 posts

Posted 09 February 2006 - 05:42 PM

That's great pater, thanks for posting it. :)
With so many post concerning the ambiguities of static/global initialization and destruction, an approach like yours could save a lot people of many hassles.
monjardin's JwN Meter (1,2,3,4,5,6):
|----|----|----|----|----|----|----|----|----|----|
*

#5 Reedbeta

    DevMaster Staff

  • Administrators
  • 5307 posts
  • LocationBellevue, WA

Posted 09 February 2006 - 07:26 PM

Time for a new code gem? :)
reedbeta.com - developer blog, OpenGL demos, and other projects

#6 MJeannig

    Member

  • Members
  • PipPip
  • 29 posts

Posted 09 February 2006 - 08:51 PM

Actually you should try to avoid complex objets build statically... Why do you need globals ?

#7 monjardin

    Senior Member

  • Members
  • PipPipPipPip
  • 1033 posts

Posted 09 February 2006 - 10:07 PM

@MJeannig: You have to initialize your interdependent classes somehow. What problem do you see with pater's method?

#8 pater

    Valued Member

  • Members
  • PipPipPip
  • 117 posts

Posted 09 February 2006 - 10:24 PM

It may seem that having a lot of static classes is bad design. In many cases, I completelly agree to this, but the advantage of the method I'm using is, that it adding an additional class can be done without modification of other code. Some of my classes will add themselves to other lists (besides the one used by the i4_init_class itself), like the list of game objects, or the list of user commands. So adding i.e. a new game object type is done by just declaring a static instance of such a class, which then knows how this new object is going to be constructed. With some macro tricks, this is only a single line of code, at the very location where the object itself is declared. I don't need to have a file where all my objects are listed, and which includes every object's .h file to be able to call the object's constructor.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users