Topic: Static data members of class templates initialization


Author: "Mike Dimmick" <mike@dimmick.demon.co.uk>
Date: 2000/12/06
Raw View
[I was originally going to email the OP directly, but decided this might
raise some issues of importance to the newsgroup, esp. the interaction of
the highlighted rule in 3.6.2/1 and its relation to template instantiations.
MJD.]

"Andrei Iltchenko" <Andrei.Iltchenko@openmarket.com> wrote in message
news:<3A1B6169.192D89AB@openmarket.com>...
> Gentlmen,
> I've two questions which I cannot find answers to in the
> "Programming languages -- C++" ISO/IEC International Standard.
>
> The questions are as follows:
>
> I have a class template which has a static data member
> //file header.h
> extern int initializer();
> template<typename T>
> struct exp {
> static int m_data;
> };
> template<typename T>
> int exp<T>::m_data = initializer();
>
> and I rely on implicit instantiation when working with this class
> in my translation units:
> //file transl_unit1.cpp
> #include <iostream>
>
> extern int initializer();
> extern void func();
> static int g_data2 = initializer();
>
> #include "header.h"
>
> static int g_data3 = initializer();
> extern int g_data4;
>
> int main()
> {
> std::cout << exp<char>::m_data << std::endl <<
> g_data2 << std::endl << g_data3 << std::endl <<
> g_data4 << std::endl;
> func();
> return 0;
> }
>
> int initializer()
> {
> static int counter;
> return counter++;
> }
>
>
>
> //file transl_unit2.cpp
> extern int initializer();
> int g_data4 = initializer();
> #include "header.h"
>
> void func()
> {
> exp<char>::m_data++;
> }
>
>
> My questions are:
> 1. Is it guaranteed that both g_data2 and g_data4 will be dynamically
> initialized
> prior to exp<char>::m_data, as the latter is implicitly instantiated in
> both
> translation units?
>
> 2. The point of instantiation of exp<char>::m_data in the translation
> unit
> transl_unit1.cpp according to the standard immediately follows the
> definition
> of the function main. Does that mean that g_data3 will also be
> initialized
> prior to exp<char>::m_data, regardless of the latter being defined
> before
> g_data3?
>
> I tried compiling the program mentioned above with Visual C++ 5.0
> and Intel C/C++ compiler 4.5. The former failed to compile it at all
> with "INTERNAL COMPILER ERROR",
> and the latter gave me the following output
> 2
> 0
> 1
> 3
> Which means that exp<char>::m_data was initialized before g_data4.

The ordering rules on global declarations (the standard calls them
'non-local static objects') may be found in section 3.6.2
[basic.start.init] - "Initialisation of non-local objects". Specifically,
paragraph 3 says:

"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."

[this paragraph appears to support the possibility of dynamic linking, where
initialisation cannot occur until the library is loaded]

However, paragraph 1 also says:

"Objects with static storage duration defined in namespace scope in the same
translation unit and dynamically initialized shall be initialized in the
order in which their definition appears in the translation unit."

You also have the interaction of templates, for which the standard says
this:

"Unless a member of a class template or a member template has been
explicitly instantiated or explicitly specialized, the specialization of the
member is implicitly instantiated when the specialization is referenced in a
context that requires the member definition to exist; in particular, the
initialization (and any associated side-effects) of a static data member
does not occur unless the static data member is itself used in a way that
requires the definition of the static data member to exist."

    -- From 14.7.1/1 [temp.inst].

I think you would be better off using the Singleton pattern where possible;
that is, changing a non-local static object for a function that looks like:

class A;

A& getA()
{
    static A rep = /* some initialisation quantity */;
    return rep;
}

Then, instead of using your g_data2 object, you would refer to it as
get_g_data2().
Secondly, note that any object without a constructor may be initialised at
compile-time, not at run-time. See 3.6.2/1.

You should also note that your func() in transl_unit2.cpp may or may not
refer to the same instantiation of exp<char>. It's most likely that it
won't; templates marked 'export' are exported [1] while those that aren't
are not. The template exp<T> in header.h has internal linkage and therefore
one copy of it will appear in each translation unit. Any references to it
will be to the copy in the translation unit which references.

>From this, I can deduce that your implementation does initialise before
main() is called, and does them in the order that they appear within the
translation unit, but that you may get different behaviour if you link
transl_unit1 and transl_unit2 in a different order. This is why, in general,
as Scott Meyers says in 'Effective C++, Second Edition':

"You do not want the behaviour of your software to be dependent on the
initialisation order of non-local static objects in different translation
units, because you have no control over that order. Let me repeat that. _You
have absolutely no control over the order in which non-local static objects
in different translation units are initialised_"

If you move to an implementation which only initialises globals the first
time they are used, at runtime, then you might get any order at all, because
the order of _use_ of the four is implementation-defined. You can probably
rely on g_data2 being initialised before g_data3, since that is guaranteed
by 3.6.2/1.

I hope this helps,

--
Mike Dimmick
Undergraduate Final-Year Student of Computing Science
Aston University, Birmingham, UK

[1] You will of course need to find a compiler that supports template
export.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]






Author: Andrei Iltchenko <Andrei.Iltchenko@openmarket.com>
Date: 2000/11/22
Raw View
Gentlmen,
I've two questions which I cannot find answers to in the
"Programming languages -- C++" ISO/IEC International Standard.

The questions are as follows:

I have a class template which has a static data member
//file header.h
extern int  initializer();
template<typename T>
struct  exp  {
   static int   m_data;
};
template<typename T>
int  exp<T>::m_data = initializer();

and I rely on implicit instantiation when working with this class
in my translation units:
//file transl_unit1.cpp
#include <iostream>

extern int  initializer();
extern void  func();
static int   g_data2 = initializer();

#include "header.h"

static int   g_data3 = initializer();
extern int   g_data4;

int  main()
{
   std::cout << exp<char>::m_data << std::endl <<
      g_data2 << std::endl << g_data3 << std::endl <<
      g_data4 << std::endl;
   func();
   return  0;
}

int  initializer()
{
   static int   counter;
   return  counter++;
}



//file transl_unit2.cpp
extern int  initializer();
int   g_data4 = initializer();
#include "header.h"

void  func()
{
   exp<char>::m_data++;
}


My questions are:
1. Is it guaranteed that both g_data2 and g_data4 will be dynamically
initialized
prior to exp<char>::m_data, as the latter is implicitly instantiated in
both
translation units?

2. The point of instantiation of exp<char>::m_data in the translation
unit
transl_unit1.cpp according to the standard immediately follows the
definition
of the function main. Does that mean that g_data3 will also be
initialized
prior to exp<char>::m_data, regardless of the latter being defined
before
g_data3?

I tried compiling the program mentioned above with Visual C++ 5.0
and Intel C/C++ compiler 4.5. The former failed to compile it at all
with "INTERNAL COMPILER ERROR",
and the latter gave me the following output
2
0
1
3
Which means that exp<char>::m_data was initialized before g_data4.

Thank you very much in advance.

Kind Regards,
Andrei Iltchenko.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]