This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Suggestion for GCC (C & C++) enhancement - static variable initialisation ordering
- From: "Manfred von Willich" <manfred at techniroot dot co dot za>
- To: <gcc at gcc dot gnu dot org>
- Date: Sat, 29 Apr 2006 16:45:41 +0200
- Subject: Suggestion for GCC (C & C++) enhancement - static variable initialisation ordering
Any interested GCC maintainers/contributors:
I have a suggestion for GCC to eliminate a pernicious problem - that of
automatically initialising static (i.e. long-lived) variables in the correct
order based on mutual dependencies, apparently not normally addressed by
compilers. This is a thorny issue, and is normally discovered the hard way
by most programmers - not the way to produce robust code. I would welcome
any correspondence/queries on the matter.
The suggestion is for a simple modification to GCC to ensure that static
variables are always initialised (and destroyed) in the correct order
determined by dependencies between the actual variables concerned - this
applies to both C and C++. Someone may already have tackled this issue,
though I don't see it on the GNU site. I would be happy to supply example
code to illustrate the concept to any interested person.
I have a very simple approach to
(a) ensure that every static variable used in initialising another is
always initialised beforehand, even when this dependency is hidden from the
compiler, and
(b) detect (unfortunately not at compile time) when correct
initialisation is impossible due to a cyclic dependency.
A more involved mechanism can also
(c) ensure that no static variable is destroyed before its last use.
The essence of the idea for (a) is:
- Access each static variable including static class members via
(inlined) wrapper code in the same way as is typical for function-local
variables (i.e. initialised once on first access using a flag). This
ensures that every static variable gets initialised before use, especially
where such use is in the initialisation of another static variable.
- Retain initialisation of static variables before calling main() (via
the wrapper code). This ensures that initialisation always occurs before
main() is called as would be expected, and does so in a single-threaded
environment, eliminating any need for a mutex.
- Preferably initialise all function-local variables at this point too -
initialisation in a multi-threaded environment using a simple flag (as
opposed to a mutex) is non-reentrant, and can fail sporadically. This
modification would have the effect that function-local statics will always
be initialised before calling main() even if never used. The alternative is
to use a mutex, which may be problematic (OS-dependent).
- I would avoid the approach apparently taken in C# and Java - that of
initialising all statics in each class as a set (this is not as robust,
since references between classes may be cyclic without cyclic dependencies
for initialisation. Note that this means that statics in a class may be
initialised after the first instances of the class are constructed, unless
used by the constructor.
The approach taken for (b) is to have an intermediate state for the flag
indicating that the initialisation of a given variable is in progress but
not yet complete. If the initialisation is triggered a second time in this
state, a cyclic dependency exists.
The approach for (c) involves triggering initialisation of every object with
a destructor early enough that the "atexit" call to the destructor occurs
after that of every object that has methods that accesses it. This can be
dealt with separately, and I will omit the detail for now.
Note that these changes are probably largely ANSI-compliant, and as such may
not have to be treated as an extension. When applied to global ("extern")
variables, additional linker information is needed (a reference to the flag
and initialisation code). This will introduce problems when linking code
generated by different versions of the compiler.
Manfred von Willich