Ted
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
neither is guaranteed by the c++ standard. it is guaranteed that
initialization of pod objects with constant expressions happens before
any other initialization and thus the entry of main, but other kinds of
initializations (ie. initialization of objects of a class with a
user-defined ctor etc.) do not have that guarantee. different
compilation units further complicate the issue.
(see standard 3.6.2 for more details)
it is dangerous practise to rely on the order of initialization of
objects in namespace scope. often a singleton data holder provides the
same functionality as global data without the hassle of ensuring proper
initialization order.
-- peter
They are guarantied to be initialized before the first use. Most
popular implementation actually do initialize them before calling
main().
> Ted wrote:
> > C++ guarantees that all globals will be initialized before main() is
> > called (right?). Apparently, in my experience, the similar thing
> > for Windows programming doesn't hold true (globals aren't
> > guaranteed to be initialized before WinMain() is called) (?).
>
> They are guarantied to be initialized before the first use. Most
> popular implementation actually do initialize them before calling
> main().
Upps.. now it is interested to me:
So, in following exampel:
SomeClass a;
int main()
{
SomeClass b;
...
}
There is no guarantee that a will be constructed before b. Right?
Regards
I couldn't get that behavior with a GUI program using WinMain()
though. So I wonder if the Windows implementation is brain-damaged.
(worked as expected for a non-GUI prog with a main() but initialization
wouldn't occur similarly in a GUI prog with WinMain()).
Tony
That's good enough though and all I need to ensure that libraries I
write will be initialized before main() with a simple construct in the
library header file such as:
static int MyLibInitialized = InitMyLib();
If my memory management library requires my error handling
library to be initialized, all is well because the mem lib includes
the error handling header and there is a guarantee (?) that
all PODs (?) will be initialized before any function in that module
is called so MyLibInitialized is initialized by calling the initialization
function. So this initialization-before-any-module-func-is-called
guarantee is important. (OK, this is separate from the "guarantee"
mentioned in my initial post, but I believe this is how I solved the
problem).
I had some problems relying on things being initialized before
main() and WinMain(). They acted differently. All was fine
with the console program but the GUI program didn't initialize
what I expected it to. I'm sure it was some C++ objects and
I think it had something to do with C++ lazily calling constructors
(upon first access?). I can probably reproduce the situation
but right now it is working fine (I believe via the initialization
"trick" shown above).
> but other kinds of
> initializations (ie. initialization of objects of a class with a
> user-defined ctor etc.) do not have that guarantee. different
> compilation units further complicate the issue.
As long as there are the above like mechanisms, all is well.
>
> (see standard 3.6.2 for more details)
>
> it is dangerous practise to rely on the order of initialization of
> objects in namespace scope. often a singleton data holder provides the
> same functionality as global data without the hassle of ensuring proper
> initialization order.
I don't think I have worried about order given that I use the initialization
technique presented. It just all works itself out.
Tony
this initialization does not qualify for the above given criterias.
while the object type is POD (int), the initializer ( = InitMyLib()) is
not a constant expression. initializing with a function call requires
dynamic initialization and is allowed to be deferred beyond main.
see standard 5.19 for the definition of constant expressions.
>
> If my memory management library requires my error handling
> library to be initialized, all is well because the mem lib includes
> the error handling header and there is a guarantee (?) that
> all PODs (?) will be initialized before any function in that module
> is called so MyLibInitialized is initialized by calling the initialization
> function. So this initialization-before-any-module-func-is-called
> guarantee is important. (OK, this is separate from the "guarantee"
> mentioned in my initial post, but I believe this is how I solved the
> problem).
yes, 'initialization-before-any-module-func-is-called' is what you can
rely on. the above MyLibInitialized example will guarantee that
InitMyLib() is called before the first usage of any function defined in
that translation unit.
still there is no guarantee about the initialization before entry of
main, but the former is probably all that you need anyways.
Refer to 3.6.2 Initialization of non-local objects and the example
...
3 It is implementation-defined whether or not the dynamic
initialization (8.5, 9.4, 12.1, 12.6.1) of an object of namespace scope
is done before the first statement of main. If the initialization is
deferred to some point in time after the first statement of main, it
shall occur before the first use of any function or object defined in
the same translation unit as the object to be initialized.
...
No it will not. Neither according to the standard, nor in
actual practice.
> still there is no guarantee about the initialization before
> entry of main, but the former is probably all that you need
> anyways.
The problem is that the former guarantee is only present if
initialization is deferred until after entering main. And no
implementation does this, because the requirements on the order
of initialization after entering main are for all intents and
purposes impossible to meet.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> > neither is guaranteed by the c++ standard. it is guaranteed
> > that initialization of pod objects with constant expressions
> > happens before any other initialization and thus the entry
> > of main,
> That's good enough though and all I need to ensure that
> libraries I write will be initialized before main() with a
> simple construct in the library header file such as:
> static int MyLibInitialized = InitMyLib();
If InitMyLib() can be called multiple times, that should work.
> If my memory management library requires my error handling
> library to be initialized, all is well because the mem lib
> includes the error handling header and there is a guarantee
> (?) that all PODs (?) will be initialized before any function
> in that module is called so MyLibInitialized is initialized by
> calling the initialization function.
A compiler must give one of two guarantees: either that all
non-local static objects are initialized before entering main,
or that IF the initialization is deferred to some point in time
after the first statement of main, of all non-local static
objects in a given translation unit will be initialized before
the first use of any object or function defined in that
translation unit. It's an either/or, and if the implementation
initializes before main, you get no guarantee concerning
initialization, except within each translation unit.
There is still a possibility of failure with your case. If the
constructor of a static object is called before entering main,
that constructor may call a function in another translation
unit, and there is no guarantee that any of the static variables
in that translation unit have been initialized.
Things like the singleton pattern, and other idioms which depend
on static initialization may be used to avoid such problems.
> So this initialization-before-any-module-func-is-called
> guarantee is important.
That guarantee is only present if the implementation defers
initialization until after entering main. None do.
> (OK, this is separate from the "guarantee" mentioned in my
> initial post, but I believe this is how I solved the problem).
> I had some problems relying on things being initialized before
> main() and WinMain().
I'm not too familiar with the Windows platform, but if you don't
have a main() (but only WinMain()), then all bets are off. You
never enter main(), since it doesn't exist, so you get no
guarantees from the standard.
> They acted differently. All was fine with the console program
> but the GUI program didn't initialize what I expected it to.
As I said, I'm not familiar with Windows programming. But I
find it hard to imagine that the invented a separate
initialization scheme for Windows programs, and I have written
programs with main() which were compiled by VC++, ran in a
Console box under Windows, and depended on initialization before
main. I rather suspect that the fact that it is a Windows
program is somehow triggering dynamic linking, and what you are
seeing is an effect of that, rather than a difference in the
basic model. (For some reason, both under Windows and under
Unix, static objects in dynamically loaded modules are not
initialized before the module is loaded. I wonder why:-).)
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> > They are guarantied to be initialized before the first use.
> > Most popular implementation actually do initialize them
> > before calling main().
All existing implementations actually do initialize before
calling main(). With certain restrictions, e.g. everything is
statically linked, etc.
> Upps.. now it is interested to me: So, in following exampel:
> SomeClass a;
> int main()
> {
> SomeClass b;
> ...
> }
> There is no guarantee that a will be constructed before b.
> Right?
In this case, there is a guarantee from the standard, since both
main and the object are in the same translation unit. The
standard gives the implementation a choice: it can initialize
before main is called, or it can initialize before the first use
(after main has been called) of any function or object in the
translation unit. (Actually, I think the wording is a bit
unclear concerning main, but IMHO the intent in this case is
clear.)
In practice, all implementations initialize before main is
called, because it is technically infeasable to meet the
requirements for the alternative: taking the address of an
object counts as use, for example, so an implementation must
ensure that the objects are initialized before the address is
taken. And of course, once main has been entered, a use in a
constructor of a static object is also a use -- formally, in the
case of dependancy cycles, an implementation would be required
to do the impossible.
Formally, too, this is implementation-defined behavior, which
means that the implementation must document what it does. Good
luck in finding such documentation -- in my experience, it's
even rarer than implementations of export.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
It seems to work though:
// myglobal.h ------------------------------------------------------------------
//
#ifndef MYGLOBAL_H
#define MYGLOBAL_H
extern int MyGlobalVar;
extern "C" bool InitMyGlobalVar();
static bool MyGlobalVarInitialized = InitMyGlobalVar();
#endif
// myglobal.cpp ----------------------------------------------------------------
//
#include <stdio.h>
int MyGlobalVar = 5;
extern "C" bool InitMyGlobalVar()
{
printf("\n%s", "InitMyGlobalVar");
// C++ guarantees that all globals in a module will be initialized before any
// func in that module is called, so just calling this func gives ensurance
// that MyGlobalVar is initialized. This func is called from every module that
// includes myglobal.h because of the static bool MyGlobalVarInitialized
// declared there.
//
return 1;
}
// myfunc.h --------------------------------------------------------------------
//
#ifndef MYFUNC_H
#define MYFUNC_H
extern "C" bool MyFunc();
#endif
// myfunc.cpp ------------------------------------------------------------------
//
#include "myfunc.h"
#include "myglobal.h"
#include <stdio.h>
extern "C" bool MyFunc()
{
printf("\n%s", "MyFunc");
// MyGlobalVar guaranteed to be initialized
// even though this func will be called before main()
printf("\n%ld", MyGlobalVar);
return 1;
}
// myclass.h -------------------------------------------------------------------
//
#ifndef MYCLASS_H
#define MYCLASS_H
class MyClass
{
public:
MyClass();
};
#endif
// myclass.cpp -----------------------------------------------------------------
//
#include "myclass.h"
#include "myglobal.h"
#include <stdio.h>
MyClass::MyClass()
{
printf("\n%s", "MyClass::MyClass");
// MyGlobalVar guaranteed to be initialized
// even though this ctor will be called before main()
printf("\n%ld", MyGlobalVar);
}
// globaltst.cpp ---------------------------------------------------------------
//
#include "myfunc.h"
#include "myclass.h"
#include <stdio.h>
bool dummy = MyFunc();
MyClass myclassinst;
int main(void)
{
printf("\n%s", "main");
return 1;
}
/* -----------------------------------------------------------------------------
The output of the above prog is:
InitMyGlobalVar
InitMyGlobalVar
MyFunc
5
MyClass::MyClass
5
main
------------------------------------------------------------------------------*/
TT
I can be called multiple times. See my other post in this thread
for some code that seems to work as expected (expected by
me that is).
>> If my memory management library requires my error handling
>> library to be initialized, all is well because the mem lib
>> includes the error handling header and there is a guarantee
>> (?) that all PODs (?) will be initialized before any function
>> in that module is called so MyLibInitialized is initialized by
>> calling the initialization function.
>
> A compiler must give one of two guarantees: either that all
> non-local static objects are initialized before entering main,
> or that IF the initialization is deferred to some point in time
> after the first statement of main, of all non-local static
> objects in a given translation unit will be initialized before
> the first use of any object or function defined in that
> translation unit.
> It's an either/or, and if the implementation
> initializes before main, you get no guarantee concerning
> initialization, except within each translation unit.
That's OK though because including a header with a static
makes that static a part of the translation unit where the
lib stuff is to be used. That static gets initialized by calling
the lib initialization func so all is good. (?)
I'm only looking for a guarantee within a given translation
unit I believe.
> There is still a possibility of failure with your case. If the
> constructor of a static object is called before entering main,
> that constructor may call a function in another translation
> unit, and there is no guarantee that any of the static variables
> in that translation unit have been initialized.
I think I get what you're saying: that my error lib initialization
func contained in err.cpp may rely on statics WITHIN err.cpp
and there is no guarantee that they are initialized. I think I may
have witnessed some of that behavior and manually initialized
statics within err.cpp in the lib initialization func for that reason.
(I don't actually have my nose in the code right now as it is
getting too late to think).
> Things like the singleton pattern, and other idioms which depend
> on static initialization may be used to avoid such problems.
I'll have to open up the patterns book and look at that again
at this juncture perhaps.
>> So this initialization-before-any-module-func-is-called
>> guarantee is important.
>
> That guarantee is only present if the implementation defers
> initialization until after entering main. None do.
Now I'm confused as to how and why it is working as expected.
>> (OK, this is separate from the "guarantee" mentioned in my
>> initial post, but I believe this is how I solved the problem).
>
>> I had some problems relying on things being initialized before
>> main() and WinMain().
>
> I'm not too familiar with the Windows platform, but if you don't
> have a main() (but only WinMain()), then all bets are off. You
> never enter main(), since it doesn't exist, so you get no
> guarantees from the standard.
And apparently, no guarantees from Windows! :(
>> They acted differently. All was fine with the console program
>> but the GUI program didn't initialize what I expected it to.
>
> As I said, I'm not familiar with Windows programming. But I
> find it hard to imagine that the invented a separate
> initialization scheme for Windows programs,
Me too! But I did have different initialization behavior between
a GUI Windows prog (has WinMain) and a console Windows
program (has main). Bizarre I thought also. That's what led me
to search for an initialization technique.
> and I have written
> programs with main() which were compiled by VC++, ran in a
> Console box under Windows, and depended on initialization before
> main.
The console programs worked fine for me also but virtually the same
program as a GUI program wouldn't work right. I'd have to revisit it
to remember what vars/objects weren't behaving correctly (if they were
class objects or not... I believe they were because I remember
thinking that C++ lazy initialization of class objects (not calling
the ctor until anytime before the object was used) had something
to do with it.
> I'mI rather suspect that the fact that it is a Windows
> program is somehow triggering dynamic linking, and what you are
> seeing is an effect of that, rather than a difference in the
> basic model. (For some reason, both under Windows and under
> Unix, static objects in dynamically loaded modules are not
> initialized before the module is loaded. I wonder why:-).)
This was my own code and not in a DLL.
TT
i do not really understand your point here. doesn't the reverse, namely
not deferring the initialization beyond entering main always guarantee
that it took place before calling into functions in that translation
unit from local code?
or are you referring to interdependend static initializations (which
the original poster did not intent to use)?
e.g.:
// unit1.cpp
struct Foo {...};
Foo foo;
// unit2.cpp
extern Foo foo;
int bar = baz(); // baz requires foo to be initialized
this confusion is just why i always avoid static initialization tricks,
but from the theoretical viewpoint i don't understand why the original
problem wouldn't work out.
-- peter
IIRC the purpose of the second option was to allow dynamic libraries in
C++. Without the current rule all dynamic libraries would have to be
loaded and fully initialised before entry to main even if the actual
thread of execution never passes through one of them. With the rule a
conforming implementation can delay initialisation of globals in a
dynamic library until it is necessary to load the library.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
no. It only guarantees that initialization will occur before
the first statement in main() is executed. No more, no less.
> or are you referring to interdependend static initializations
> (which the original poster did not intent to use)?
I'm not sure what the original poster intented to use. Code to
initialize static variables will be run before the first
statement in main, and must be taken into account. His example,
in his answer to my posting, showed the problem quite well.
> e.g.:
> // unit1.cpp
> struct Foo {...};
> Foo foo;
> // unit2.cpp
> extern Foo foo;
> int bar = baz(); // baz requires foo to be initialized
> this confusion is just why i always avoid static
> initialization tricks, but from the theoretical viewpoint i
> don't understand why the original problem wouldn't work out.
See my response to his response.
There are, of course, many solutions to the problem. The
easiest to understand is, as you say, to avoid data at namespace
scope completely. Alternatively (and one I use a lot) is to
ensure that such data is all of POD type, initialized with
constant expressions. And of course, the typical C++
implementations of the singleton pattern also address this
problem.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> > peter steiner wrote:
[...]
> >> yes, 'initialization-before-any-module-func-is-called' is
> >> what you can rely on. the above MyLibInitialized example
> >> will guarantee that InitMyLib() is called before the first
> >> usage of any function defined in that translation unit.
> > No it will not. Neither according to the standard, nor in
> > actual practice.
> It seems to work though:
It works sometimes. For a given compiler, I know how to
contruct cases for which it appears to work. The problem
remains that you have no control over the order of
initialization between modules.
> // myglobal.h ------------------------------------------------------------------
> //
> #ifndef MYGLOBAL_H
> #define MYGLOBAL_H
>
> extern int MyGlobalVar;
> extern "C" bool InitMyGlobalVar();
> static bool MyGlobalVarInitialized = InitMyGlobalVar();
>
> #endif
>
> // myglobal.cpp ----------------------------------------------------------------
> //
> #include <stdio.h>
>
> int MyGlobalVar = 5;
>
> extern "C" bool InitMyGlobalVar()
> {
> printf("\n%s", "InitMyGlobalVar");
> // C++ guarantees that all globals in a module will be
> // initialized before any func in that module is called,
No it doesn't. The C++ standard guarantees that IF
initialization is deferred until after the first statement in
main... The fact is that the above guarantee is impossible to
implement, and no one tries to. All compilers do static
initialization before main, and so this guarantee does not hold.
> // so
> // just calling this func gives ensurance that MyGlobalVar
> // is initialized. This func is called from every module
> // that includes myglobal.h because of the static bool
> // MyGlobalVarInitialized declared there.
And what about the modules which don't include myglobal.h?
What you are doing is really just a simplified variant of the
tricky counter technique used to initialize cin, cout and cerr
in the USL implementation of <iostream.h>. It works most of the
time, but there are known weaknesses.
> return 1;
> }
> // myfunc.h --------------------------------------------------------------------
> //
> #ifndef MYFUNC_H
> #define MYFUNC_H
> extern "C" bool MyFunc();
> #endif
> // myfunc.cpp ------------------------------------------------------------------
> //
> #include "myfunc.h"
> #include "myglobal.h"
> #include <stdio.h>
> extern "C" bool MyFunc()
> {
> printf("\n%s", "MyFunc");
>
> // MyGlobalVar guaranteed to be initialized
> // even though this func will be called before main()
Sorry, but if this function is called from the initialization of
a static variable in another translation unit, and that unit
does not include "myglobal.h", all bets are off. It might work,
and it might not -- with the compilers I've actually analysed,
whether it works or not depends on the link order.
> printf("\n%ld", MyGlobalVar);
> return 1;
> }
> // myclass.h -------------------------------------------------------------------
> //
> #ifndef MYCLASS_H
> #define MYCLASS_H
> class MyClass
> {
> public:
> MyClass();
> };
> #endif
>
> // myclass.cpp -----------------------------------------------------------------
> //
> #include "myclass.h"
> #include "myglobal.h"
> #include <stdio.h>
> MyClass::MyClass()
> {
> printf("\n%s", "MyClass::MyClass");
> // MyGlobalVar guaranteed to be initialized
> // even though this ctor will be called before main()
Wrong again. There's no guarantee here.
There is a guarantee if the translation unit which defines the
static object includes "myglobal.h". But this supposes that it
knows of this special dependancy.
Note that exactly this problem existed with the USL
implementation of <iostream.h>. (And exists with all
implementations of <iostream> today that I know of.) If the
constructor tried to use cerr, there was no guarantee that it
would actually have been constructed. With CFront (at least
under Sun OS and Solaris), construction of static objects
occurred in the reverse order that the modules were linked. In
a typical application, there was a very good chance that some
low level module, linked in at the end, would include
<iostream.h>; <iostream.h> included the necessary static
definition to trigger initialization of cin, cout and cerr, and
the error would go unobserved. (Note that the implementation of
the classes in <iostream.h> was found in libC.a, which was
typically the last library containing C++ to be linked. And of
course, the implementation of <iostream.h> included
<iostream.h>. So the only time I've seen code which failed with
CFront was when I wrote some additions to libC.a.)
This, of course, is all very much dependant on a particular
compiler. If you want to use std::cerr here, you MUST ensure
that std::ios_base::Init has been initialized at least once,
e.g.:
static std::ios_base::Init dummyToEnsureInitialization ;
Similarly, if you want to be sure your code works, you must
declare something which will ensure the intialization:
static bool dummyToEnsureInitialization = InitMyGlobalVar();
In the constructor, in both cases.
> printf("\n%ld", MyGlobalVar);
> }
> // globaltst.cpp ---------------------------------------------------------------
> //
> #include "myfunc.h"
> #include "myclass.h"
> #include <stdio.h>
> bool dummy = MyFunc();
> MyClass myclassinst;
> int main(void)
> {
> printf("\n%s", "main");
> return 1;
> }
> /* -----------------------------------------------------------------------------
> The output of the above prog is:
> InitMyGlobalVar
> InitMyGlobalVar
> MyFunc
> 5
> MyClass::MyClass
> 5
> main
So you got lucky. Try linking the different modules in
different orders. At least with Sun CC and g++ under Solaris,
you'll get different results, depending on the order of linking.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> >> > neither is guaranteed by the c++ standard. it is
> >> > guaranteed that initialization of pod objects with
> >> > constant expressions happens before any other
> >> > initialization and thus the entry of main,
> >> That's good enough though and all I need to ensure that
> >> libraries I write will be initialized before main() with a
> >> simple construct in the library header file such as:
> >> static int MyLibInitialized = InitMyLib();
> > If InitMyLib() can be called multiple times, that should work.
> I can be called multiple times. See my other post in this
> thread for some code that seems to work as expected (expected
> by me that is).
I have. It only works by chance. It's not guaranteed, and (at
least with the compilers I use) may fail depending on the order
the modules are linked.
> >> If my memory management library requires my error handling
> >> library to be initialized, all is well because the mem lib
> >> includes the error handling header and there is a guarantee
> >> (?) that all PODs (?) will be initialized before any
> >> function in that module is called so MyLibInitialized is
> >> initialized by calling the initialization function.
> > A compiler must give one of two guarantees: either that all
> > non-local static objects are initialized before entering
> > main, or that IF the initialization is deferred to some
> > point in time after the first statement of main, of all
> > non-local static objects in a given translation unit will be
> > initialized before the first use of any object or function
> > defined in that translation unit.
> > It's an either/or, and if the implementation initializes
> > before main, you get no guarantee concerning initialization,
> > except within each translation unit.
> That's OK though because including a header with a static
> makes that static a part of the translation unit where the lib
> stuff is to be used. That static gets initialized by calling
> the lib initialization func so all is good. (?)
It's a bit more complicated than that. The static gets
initialized before any other global variables in the translation
unit. There's no guarantee with regards to functions, however;
if the initialization of a global variable in another
translation unit calls a function in your translation unit, it
is unspecified whether the static variable will have been
initialized or not in your translation unit.
> I'm only looking for a guarantee within a given translation
> unit I believe.
If the initialization of a given translation unit never calls a
function in another translation unit, that's sufficient.
Typically, this is not the case.
Why do you imagine so much has been written about the singleton
pattern in C++?
> > There is still a possibility of failure with your case. If
> > the constructor of a static object is called before entering
> > main, that constructor may call a function in another
> > translation unit, and there is no guarantee that any of the
> > static variables in that translation unit have been
> > initialized.
> I think I get what you're saying: that my error lib
> initialization func contained in err.cpp may rely on statics
> WITHIN err.cpp and there is no guarantee that they are
> initialized. I think I may have witnessed some of that
> behavior and manually initialized statics within err.cpp in
> the lib initialization func for that reason. (I don't
> actually have my nose in the code right now as it is getting
> too late to think).
See my other response. The problem is very, very old. It
affects, amongst other things, cin, cout and cerr (as they were
back then).
> > Things like the singleton pattern, and other idioms which
> > depend on static initialization may be used to avoid such
> > problems.
> I'll have to open up the patterns book and look at that again
> at this juncture perhaps.
It's often an appropriate solution. Ensuring that all of the
essential data is of POD type, and initialized with constants,
also works. As do any number of other solutions using lazy
initialization.
One simple trick I used way back when (before I'd heard of the
singleton pattern) was to use a non-static fassade class, and
require all accesses to my library to pass through it. The
fassade class didn't do anything but forward the function calls
to the static instance, but it's constructor ensured that
everything was correctly initialized.
> >> So this initialization-before-any-module-func-is-called
> >> guarantee is important.
> > That guarantee is only present if the implementation defers
> > initialization until after entering main. None do.
> Now I'm confused as to how and why it is working as expected.
Pure chance. The most frequent effect of undefined behavior is
that the code works in all of your tests, then fails
catestrophically during the big demo in front of your most
important customer. In this case, I don't think you have to
worry about that, but it could easily fail at the slightest
change in the order of linking.
> >> (OK, this is separate from the "guarantee" mentioned in my
> >> initial post, but I believe this is how I solved the
> >> problem).
> >> I had some problems relying on things being initialized
> >> before main() and WinMain().
> > I'm not too familiar with the Windows platform, but if you
> > don't have a main() (but only WinMain()), then all bets are
> > off. You never enter main(), since it doesn't exist, so you
> > get no guarantees from the standard.
> And apparently, no guarantees from Windows! :(
There probably are, but finding where they are documented may
not be simple.
> >> They acted differently. All was fine with the console
> >> program but the GUI program didn't initialize what I
> >> expected it to.
> > As I said, I'm not familiar with Windows programming. But I
> > find it hard to imagine that the invented a separate
> > initialization scheme for Windows programs,
> Me too! But I did have different initialization behavior
> between a GUI Windows prog (has WinMain) and a console Windows
> program (has main). Bizarre I thought also. That's what led
> me to search for an initialization technique.
If you really do have an order of initialization problem, it's
quite possible that it appears and disappears depending on the
order things are linked into the final module. Or any other
random feature I've not thought of. The fact that it works in
one environment, and not in another, doesn't really surprise me
too much.
> > and I have written programs with main() which were compiled
> > by VC++, ran in a Console box under Windows, and depended on
> > initialization before main.
> The console programs worked fine for me also but virtually the
> same program as a GUI program wouldn't work right. I'd have
> to revisit it to remember what vars/objects weren't behaving
> correctly (if they were class objects or not... I believe they
> were because I remember thinking that C++ lazy initialization
> of class objects (not calling the ctor until anytime before
> the object was used) had something to do with it.
> > I'mI rather suspect that the fact that it is a Windows
> > program is somehow triggering dynamic linking, and what you
> > are seeing is an effect of that, rather than a difference in
> > the basic model. (For some reason, both under Windows and
> > under Unix, static objects in dynamically loaded modules are
> > not initialized before the module is loaded. I wonder
> > why:-).)
> This was my own code and not in a DLL.
As I said, I'm not familiar with the Windows platform. I have
written JNI code under it (invoked from Java, and not very far
from pure C), and console applications -- and some of the
console applications did depend on global variables being
initialized before main was entered.
I still rather doubt that the actual organizaton is different
for a Windows program. What is likely is that either you have
a real order of initialization problem, and linking a Windows
program pulls in modules in a different order, or causes the
modules to be initialized in a different order, OR linking as a
Windows program has different defaults, and implicitly causes
some of your modules to be handled as if they were a DLL. Or,
of course, some other difference I've not thought of.
You're initial posting said that the variables weren't being
initialized before main was entered. With regards to that, I'm
very sceptical, unless the modules are somehow ending up in a
DLL. All of the concrete symptoms you describe, however, can
easily be attributed to an order of initialization problem.
Including the fact that your "fix" seems to work.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> >In practice, all implementations initialize before main is
> >called, because it is technically infeasable to meet the
> >requirements for the alternative: taking the address of an
> >object counts as use, for example, so an implementation must
> >ensure that the objects are initialized before the address is
> >taken. And of course, once main has been entered, a use in a
> >constructor of a static object is also a use -- formally, in
> >the case of dependancy cycles, an implementation would be
> >required to do the impossible.
> IIRC the purpose of the second option was to allow dynamic
> libraries in C++. Without the current rule all dynamic
> libraries would have to be loaded and fully initialised before
> entry to main even if the actual thread of execution never
> passes through one of them. With the rule a conforming
> implementation can delay initialisation of globals in a
> dynamic library until it is necessary to load the library.
That's roughly the excuse I heard, too. If true, I think it was
ill advised, for two reasons:
1. Dynamic linking isn't taken into consideration anywhere
else. Formally, dynamic linking violates the phases of
translation in 2.1; in practice, the as if rule gives you
some leeway, but IMHO not enough for an implementation using
dynamic linking to be fully compliant. IMHO, dynamic
linking is no different from threading: an extention which
involves formally undefined behavior, which has been defined
(hopefully) by the implementation.
2. The rule as written isn't implementable, since it makes no
allowance for circular dependancies. While I believe that
some sense can be made of it, even in such cases, IMHO, it
just isn't worth it.
All things considered, if you want to support dynamic linking,
you need special rules for dynamic linking -- trying to patch it
in without actually mentionning it or even formally allowing it
just doesn't work. (I think I said so then, but it's been so
long ago that I don't really remember.)
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
The order dependency is what I was trying to remove by just
including the right header file (have it take care of itself). The
goal being getting a reliable way to initialize (automagically)
C libraries.
>> // myglobal.h ------------------------------------------------------------------
>> //
>> #ifndef MYGLOBAL_H
>> #define MYGLOBAL_H
>>
>> extern int MyGlobalVar;
>> extern "C" bool InitMyGlobalVar();
>> static bool MyGlobalVarInitialized = InitMyGlobalVar();
>>
>> #endif
>>
>> // myglobal.cpp ----------------------------------------------------------------
>> //
>> #include <stdio.h>
>>
>> int MyGlobalVar = 5;
>>
>> extern "C" bool InitMyGlobalVar()
>> {
>> printf("\n%s", "InitMyGlobalVar");
>
>> // C++ guarantees that all globals in a module will be
>> // initialized before any func in that module is called,
>
> No it doesn't. The C++ standard guarantees that IF
> initialization is deferred until after the first statement in
> main... The fact is that the above guarantee is impossible to
> implement, and no one tries to. All compilers do static
> initialization before main, and so this guarantee does not hold.
Yeah I know. I wrote this code passage before starting the thread
here and didn't bother to change the comments. I posted the
code to show what I was trying to do (I should have removed the
old comments first).
New example that works "as expected":
// mylib.h ---------------------------------------------------------------------
//
extern int Flags; // global var declaration we are trying to guarantee
// initialization of.
extern "C" bool InitializeMyLib(); // fwd declaration for following
// statement.
// MyLibInitialized never used in actual tests for lib initialization,
// just used to trigger calling of initialization function.
//
static bool MyLibInitialized = InitializeMyLib();
// mylib.cpp -------------------------------------------------------------------
//
#include <stdio.h>
int Flags = 0; // the actual global var definition
extern "C" bool InitializeMyLib()
{ printf("\n%s", "InitializeMyLib");
// can't test against MyLibInitialized cuz it can contain any garbage
// so use a local static var to test against.
//
static bool init_done = 0;
if(init_done == 1) // no need to init if true
return 1;
Flags = 5; // do initialization of global
init_done = 1; // set local indicator
return 1;
}
// lib2.h ----------------------------------------------------------------------
//
#include <mylib.h> // ensure mylib (Flags) initialization for any translation
// unit using Lib2Func(). (This is the key to getting the
// initialization to work in myclass.cpp. mylib.h inclusion
// is not strictly needed by lib2.h but is for callers of
// Lib2Func() so that Flags is initialized). How much this
// technique can be relied upon with different compilers is
// the question.
extern "C" void Lib2Func();
// lib2.cpp --------------------------------------------------------------------
//
#include <lib2.h>
#include <stdio.h>
extern "C" void Lib2Func()
{ printf("\n%s", "Lib2Func");
// Flags guaranteed (?) to be initialized cuz of inclusion of mylib.h
// via lib2.h.
//
printf("\n%ld", Flags);
}
// myclass.h
//
class MyClass
{
public:
MyClass();
};
// myclass.cpp -----------------------------------------------------------------
//
#include "myclass.h"
#include "lib2.h"
#include <stdio.h>
// calling Lib2Func() from this translation unit
//
MyClass::MyClass()
{
printf("\n%s", "MyClass::MyClass");
Lib2Func();
}
static MyClass my_class_instance; // Flags initialized? Yes!
// globaltst.cpp ---------------------------------------------------------------
//
#include <myclass.h>
#include <stdio.h>
MyClass my_class_inst; // Flags initialized? Yes!
int main()
{ printf("\n%s", "main");
return 1;
}
/*
The output of the above prog is:
InitializeMyLib
MyClass::MyClass
Lib2Func
5
InitializeMyLib
MyClass::MyClass
Lib2Func
5
main
*/
>> // so
>> // just calling this func gives ensurance that MyGlobalVar
>> // is initialized. This func is called from every module
>> // that includes myglobal.h because of the static bool
>> // MyGlobalVarInitialized declared there.
>
> And what about the modules which don't include myglobal.h?
Any module indirectly making use of the global will be OK as
long as the indirect header includes the global header (this
is the key to making it work. But will it always work is the
question across different compilers).
Understood. But adding myglobal.h to myfunc.h would fix the
problem (at least with my compiler it does). (The new example
does this).
>
>> printf("\n%ld", MyGlobalVar);
>> return 1;
>> }
>
>> // myclass.h -------------------------------------------------------------------
>> //
>> #ifndef MYCLASS_H
>> #define MYCLASS_H
>
>> class MyClass
>> {
>> public:
>> MyClass();
>> };
>
>> #endif
>>
>> // myclass.cpp -----------------------------------------------------------------
>> //
>> #include "myclass.h"
>> #include "myglobal.h"
>> #include <stdio.h>
>
>> MyClass::MyClass()
>> {
>> printf("\n%s", "MyClass::MyClass");
>> // MyGlobalVar guaranteed to be initialized
>> // even though this ctor will be called before main()
>
> Wrong again. There's no guarantee here.
>
> There is a guarantee if the translation unit which defines the
> static object includes "myglobal.h". But this supposes that it
> knows of this special dependancy.
If I'm understanding it correctly, it's not that hard to enforce
(key is not to hide global headers in .cpp files, but rather
bring them out to the .h file).
Isn't the ordering of the static before any other static or other object
(via the global header file inclusion) enough?
>
>> // globaltst.cpp ---------------------------------------------------------------
>> //
>> #include "myfunc.h"
>> #include "myclass.h"
>> #include <stdio.h>
>
>> bool dummy = MyFunc();
>
>> MyClass myclassinst;
>
>> int main(void)
>> {
>> printf("\n%s", "main");
>> return 1;
>> }
>
>> /* -----------------------------------------------------------------------------
>> The output of the above prog is:
>
>> InitMyGlobalVar
>> InitMyGlobalVar
>> MyFunc
>> 5
>> MyClass::MyClass
>> 5
>> main
>
> So you got lucky. Try linking the different modules in
> different orders. At least with Sun CC and g++ under Solaris,
> you'll get different results, depending on the order of linking.
I'm wondering if my new example suffers from the same woes. I'll
have to think about the guarantees you expressed against my new
example (or you could!), cuz I just was doing trial-and-error testing
with one compiler rather than thinking about the standard's
guarantees.
T
extern "C" void Lib2Func();
/*
The output of the above prog is when linked in "right" order:
InitializeMyLib
MyClass::MyClass
Lib2Func
5
InitializeMyLib
MyClass::MyClass
Lib2Func
5
main
The output of the above prog is when linked in "wrong" order:
MyClass::MyClass
Lib2Func
0
InitializeMyLib
InitializeMyLib
MyClass::MyClass
Lib2Func
5
main
*/
// mylib.h ---------------------------------------------------------------------
//
#ifndef MYLIB_H_
#define MYLIB_H_
extern "C" int& GetFlags(); // guarantees initialization of Flags var.
#endif
// mylib.cpp -------------------------------------------------------------------
//
#include <stdio.h>
#include <mylib.h>
static int Flags = 0; // the actual global var definition
extern "C" void InitializeMyLib()
{ printf("\n%s", "InitializeMyLib");
Flags = 5; // do initialization
}
// I know there are potential problems with the following function in
// a multi-threaded environment. I'll look at that later. I actually made
// a macro out of the following, but a template would work for those
// who use that sort of thing.
//
extern "C" int& GetFlags()
{ printf("\n%s", "GetFlags");
// can't test against Flags directly cuz it can contain any garbage
// so use a local static var to test against. (?) Or OK to use cuz
// static initialization will happen before this code executes?
//
static bool init_done = 0;
if(init_done)
return Flags;
InitializeMyLib();
init_done = 1;
return Flags;
}
// lib2.h ----------------------------------------------------------------------
//
#ifndef LIB2_H_
#define LIB2_H_
extern "C" int Lib2Func();
#endif
// lib2.cpp --------------------------------------------------------------------
//
#include <stdio.h>
#include <mylib.h>
#include <lib2.h>
extern "C" int Lib2Func()
{ printf("\n%s", "Lib2Func");
printf("\n%ld", GetFlags());
return 1;
}
// myclass.h
//
#ifndef LIB2_H_
#define LIB2_H_
class MyClass
{
public:
MyClass();
};
#endif
// myclass.cpp -----------------------------------------------------------------
//
#include <stdio.h>
#include <myclass.h>
#include <lib2.h>
// calling Lib2Func() from this translation unit
//
MyClass::MyClass()
{ printf("\n%s", "MyClass::MyClass");
Lib2Func();
}
static MyClass my_class_instance;
// globaltst.cpp ---------------------------------------------------------------
//
#include <stdio.h>
#include <myclass.h>
#include <lib2.h>
int var = Lib2Func();
MyClass my_class_inst;
int main()
{ printf("\n%s", "main");
return 1;
}
I didn't find the singleton pattern to be all that useful for initialization
issues (only for ensuring a single instance or X instances). The
"access global through a function" works fine. Trying to keep the
global directly accessible as I was before is nightmarish (vigilant
header file inclusion and link order headaches).
Take a look at the answer to the first question in this link:
http://www.microsoft.com/msj/0297/c/c0297.aspx
Might give you some clues... It seems to imply main/Winmain aren't
really different.
>>Ted wrote:
>>>"kanze" <ka...@gabi-soft.fr> wrote in message
>>>news:1135704038.2...@f14g2000cwb.googlegroups.com...
>>>>peter steiner wrote:
>> [...]
>>And what about the modules which don't include myglobal.h?
> Any module indirectly making use of the global will be OK as
> long as the indirect header includes the global header (this
> is the key to making it work. But will it always work is the
> question across different compilers).
The problem is ensuring that the ultimate source of the use of
global before main includes the necessary header. Adding the
including in other header files you use can help, but the basic
problem remains unchanged.
[...]
>>Sorry, but if this function is called from the initialization
>>of a static variable in another translation unit, and that
>>unit does not include "myglobal.h", all bets are off. It
>>might work, and it might not -- with the compilers I've
>>actually analysed, whether it works or not depends on the link
>>order.
> Understood. But adding myglobal.h to myfunc.h would fix the
> problem (at least with my compiler it does). (The new example
> does this).
In the case where the translation unit whose static constructors
trigger the call includes myfunc.h. The more different headers
which include myglobal.h, the greater the chance that this
holds. But ultimately, you have to know which translation units
have initialisers for static objects which might indirectly use
your globals, and ensure somehow that myglobal.h is included,
directly or indirectly, from one of these.
(If myfunc.h is the only user of myglobal.h, you're OK. But
this is an important restriction.)
[...]
>>There is a guarantee if the translation unit which defines the
>>static object includes "myglobal.h". But this supposes that
>>it knows of this special dependancy.
> If I'm understanding it correctly, it's not that hard to
> enforce (key is not to hide global headers in .cpp files, but
> rather bring them out to the .h file).
That covers one level of indirection. What about more?
>>> printf("\n%ld", MyGlobalVar);
>>>}
Only if the call occurs during the initialization of a static
object in a translation unit which includes the header.
Note the critical point: the inclusion must be in the
translation unit which contains the static being initialized.
NOT in the translation unit which uses the function of the
object. Encapsulation means that the translation unit which
includes the object may have no knowledge of which translation
units may be ultimately called, or which static data may
ultimately be used.
[...]
> I'm wondering if my new example suffers from the same woes.
> I'll have to think about the guarantees you expressed against
> my new example (or you could!), cuz I just was doing
> trial-and-error testing with one compiler rather than thinking
> about the standard's guarantees.
The analysis is fairly simple: the compiler orders the
translation units in some arbitrary (and possibly random)
fashion. It then invokes the initialisers for the static
objects in each translation unit in their order of definition.
It makes no guarantees with regards to functions which are being
called from these initializations.
In practice, I've generally found it worthwhile either to ensure
that there are no dependancies, or to exploit zero
initialization or static initialization in someway to recognize
whether the initialization has taken place, and initialize if it
hasn't. (This is the way the singleton idiom works, zero
initialization ensures that the instance pointer is null until
it has explicitly been assigned some other value.)
--
James Kanze mailto: james...@free.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
[...]
> I didn't find the singleton pattern to be all that useful for
> initialization issues (only for ensuring a single instance or
> X instances).
That's at least partially because you are only dealing with an
int. If the data is something more complex, the issue isn't
quite the same.
> The "access global through a function" works fine.
Which is the basis of the singleton pattern. In the singleton
pattern, the "global" is a pointer to the single instance. (The
singleton pattern has its roots elsewhere, but this is its
actual effect when used in C++.)
--
James Kanze mailto: james...@free.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
Ted
K, I think I realize that.
>
>> The "access global through a function" works fine.
>
> Which is the basis of the singleton pattern. In the singleton
> pattern, the "global" is a pointer to the single instance. (The
> singleton pattern has its roots elsewhere, but this is its
> actual effect when used in C++.)
Just by the name though, I would assume that the concept behind
singleton is ensurance of a certain number of instances and that
the access/initialization techniques are used to guarantee this.
Basically though, in the simple case, a class seems overkill. The
question that still remains in my mind is what the good techniques
of initialization in C are.
T
> > [...]
> >> The "access global through a function" works fine.
> > Which is the basis of the singleton pattern. In the singleton
> > pattern, the "global" is a pointer to the single instance. (The
> > singleton pattern has its roots elsewhere, but this is its
> > actual effect when used in C++.)
> Just by the name though, I would assume that the concept
> behind singleton is ensurance of a certain number of instances
> and that the access/initialization techniques are used to
> guarantee this.
Originally, the singleton pattern is a means of ensuring that
there is exactly one instance of the type: no more, no less.
And the pattern is language independant: I've used singletons in
Java, and presumably, they can exist in just about any OO
language.
In practice, this end could be achieved in C++ by simply making
the constructor private, and declaring a static member with the
single instance. I actually do this for objects which should
register themselves with some sort of registry, and are then
only accessed through the registry. But this does result in a
potential order of initialization problem. And it doesn't work
in Java, or other OO languages which don't support static
instances of user defined types. On the other hand, the
solution which does work with Java can also be used in C++, and
although it is more complicated, it "just happens" to solve the
order of initialization problem. With the result that within the
C++ community, one tends to think of the singleton pattern as
something which is used to solve the order of initialization
problem, despite its name and origines.
> Basically though, in the simple case, a class seems overkill.
If all you need is an int, a class is definitely overkill.
> The question that still remains in my mind is what the good
> techniques of initialization in C are.
There are enough of them that it would take a book to explain
them all. Generally speaking, though, I favor making static
objects POD types and initializing them with constant
expressions whenever possible. No order of initialization
problems, and no threading problems (which can sometimes occur
with lazy initialization through a function). Thus, for
example, if I need a constant, pre-initialized map of strings to
int's, I'll use a:
struct Element
{
char const* key ;
int value ;
} ;
Element table[] = { ... } ;
and std::find_if or std::lower_bound, rather than
std::map< std::string, int >.
Note that a POD type can contain an implicit conversion
operator; if more complicated types are involved, a POD type
containing the necessary information to create one of them can
be used here, provided it provides the necessary conversion
operator. Even if I'm using an std::map (say in a more complex
singleton), I'll usually use a C style array of something like:
struct InitializerElement
{
char const* key ;
int value ;
operator MyMap::value_type() const
{
return MyMap::value_type( key, value ) ;
}
} ;
simply because the initialization is easier to read and write:
InitializerElement init[] =
{
{ "one", 1 },
{ "two", 2 },
{ "three", 3 },
} ;
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> The analysis is fairly simple: the compiler orders the
> translation units in some arbitrary (and possibly random)
> fashion. It then invokes the initialisers for the static
> objects in each translation unit in their order of definition.
> It makes no guarantees with regards to functions which are being
> called from these initializations.
>
> In practice, I've generally found it worthwhile either to ensure
> that there are no dependancies, or to exploit zero
> initialization or static initialization in someway to recognize
> whether the initialization has taken place, and initialize if it
> hasn't. (This is the way the singleton idiom works, zero
> initialization ensures that the instance pointer is null until
> it has explicitly been assigned some other value.)
// mylib.cpp
//
static bool MyLibInitialized = 0;
void MyLibFunc()
{
if(!MyLibInitialized) // is this bool initialized?
InitMyLib();
// do something...
}
In the above scenario, can MyLibInitialized be used to test for
initialization since it is possible that MyLibFunc() can be called
from a static C++ object's constructor? I'm thinking that it can't
unless zero initialization gives some greater guarantee than
non-zero POD static initialization.
Ted
> >>>Ted wrote:
Sure.
The reverse would also work here:
static bool myNeedsInit = true ;
void f()
{
if ( myNeedsInit ) {
// initialize ...
}
// ...
}
> I'm thinking that it can't unless zero initialization gives
> some greater guarantee than non-zero POD static
> initialization.
Conceptually, the initialization of variables with static
lifetime takes place in three steps:
1. Zero initialization. All arithmetic types, enumeration
types, pointers and (I think) pointers to members are
initialized as if 0, converted to the correct type as if by
static_cast, were assigned to them. This takes place before
any other initialization.
More complex types are zero initialized by decomposition:
each member is zero initialized. For unions, the first
declared non-static member (only) is zero initialized.
Note that references are NOT zero initialized.
2. "Static" initialization. This initialization concerns only
POD types with constant initializers.
3. "Dynamic" initialization. The objects are initialized in
the order of their definition within a translation unit; the
order between translation units is undefined, and may
vary, even from one invocation to the next.
This is the only phase in which user defined code may be
executed.
The result is that user initialization code can count on any
initialization taking place in the preceding phase. As I
pointed out in aother posting, this means that you can safely
use std::find on a:
struct AttrValuePair
{
char const* attr ;
int value ;
} ;
static AttrValuePair const
table[] = { ... } ;
even in code executed during the initialization of static
variables.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34