>Scott Meyers describes a good technique for ensuring that static
>Objects are initialized in the correct order in "Effective C++".
>In the first edition it's item 47: "Ensure that global objects are
>initialized before they're used". The technique has been used by
>many implementations of the iostreams library (where it ensures
>that global objects like cin, cout and cerr are properly initialized
>before any code uses it, even if that code is in another static
>object). The technique relies on standard C++ behavior, so it
>works with almost any compiler.
>
>The order in which static objects within a module are initialized
>can be controlled by declaring them all in the same source file
>in the appropriate order. The trick to ensuring that all the
>static objects in a module are initialized before you use them
>is to define a helper class for the module.
>
>So, in the header file <Module.h> we have:
>
> // class defininitions for module
>
> // declarations for Module
>
> // helper class to ensure static objects are initialized
> // before they are used
> class ModuleInit
> {
> private:
> static unsigned int count;
>
> public:
> ModuleInit();
> ~ModuleInit();
> }
>
> // declare a file static instance of ModuleInit()
> static ModuleInit() module_init;
>
>Then in the implementation file for the module we have
>
> // This will be initialized to zero before any constructors run
> unsigned int ModuleInit::count;
>
> ModuleInit::ModuleInit()
> {
> if (count++ == 0)
> {
> // initialize a static objects in Module
> }
> }
>
> ModuleInit::~ModuleInit()
> {
> if (--count == 0)
> {
> // destroy static objects in Module
> }
> }
>
>As long as any code that uses objects defined in <Module.h> includes
>this header file before declaring its own static objects, all the
>static objects in <Module.h> will be initialized before they can
>be used.
>
>Stephen C. Steel
I knew about the trick of putting all static initializers in a library into
single cpp file but there was a problem with initializers across libraries.
In my wxCommunicator, I use sipXtapi.dll and also link against sipxtacklib &
sipxportlib statically (I use Url class directly).
This problem with static initializers can be easily demonstrated in
wxCommunicator by making SipMessage::spSipMessageFieldProps statically
initialized (not by new when certain method gets called)
SipMessage::SipMessageFieldProps SipMessage::spSipMessageFieldProps;
In that case, spSipMessageFieldProps is initialized twice, once inside dll, and
2nd time in the exe. Initialization inside dll works fine, but in exe there was
a nice crash in OsUtilWnt::synchObjAcquire, as rTimeout wasn't initialized yet
(it was only initialized in dll).
So I used the approach you described and created a PortLib class which has
static PortLib PortLib_init;
in the PortLib.h file outside the class, which means constructor will get
called for every cpp file that includes it. Making it static is a nice trick,
because it won't collide with other PortLib_init's in other cpp files.
Constructor then looks like this:
PortLib::PortLib(void)
{
if (count++ == 0)
{
OsTime::OS_INFINITY = new OsTime(0x7FFFFFFF,0x7FFFFFFF);
}
}
I changed OS_INFINITY type to pointer to OsTime and made all required changes
in all libraries.
I included PortLib.h in OsUtilWnt.cpp and SipMessage.cpp (here it was needed as
well)
After these changes, I didn't get a crash in OsUtilWnt::synchObjAcquire
anymore, when I placed breakpoints I could see that this time OS_INFINITY was
initialized properly.
This time it crashed in
UtlLink* UtlLink::get()
as spLinkPool wasn't initialized yet, but this can be solved easily using the
same technique. So we can use this approach and don't need to use any compiler
dependent "tricks" (like #pragma init(lib) for MSVC) or init/shutdown methods.
Jaro
_______________________________________________
sipxtapi-dev mailing list
[email protected]
List Archive: http://list.sipfoundry.org/archive/sipxtapi-dev/