Boost logo

Boost :

From: JOAQUIN M. LOPEZ MUÑOZ (joaquin_at_[hidden])
Date: 2008-07-12 06:35:40


________________________________________
De: boost-bounces_at_[hidden] [boost-bounces_at_[hidden]] En nombre de JOAQUIN M. LOPEZ MUÑOZ [joaquin_at_[hidden]]
Enviado el: viernes, 11 de julio de 2008 17:35
Para: boost_at_[hidden]
Asunto: Re: [boost] [pool] segfault (fun with static initialization ordering)

_______________________________________

> The following is a case where the precende rule *cannot* be applied
> for logical reasons:
>
> template<typename T>
> struct foo{
> static int x;
> };
>
> template<typename T>
> int foo<T>::x=T::x;
>
> struct bar
> {
> static int x;
> };
>
> int bar::x=666;
>
> static int x=foo<bar>::x;

Please disregard this example, it is flawed because bar::x is statically initialized
an because ultimately the compiler is not required to perform the dependency
analysis suggested above. I've been playing with the following:

  #include <iostream>

  #if defined(CASE1)

  struct bar{static int x;};
  static int f(){return 666;}
  int bar::x=f();
  template<typename T>struct foo{static int x;};
  template<typename T>int foo<T>::x=T::x;

  #elif defined(CASE2)

  template<typename T>struct foo{static int x;};
  template<typename T>int foo<T>::x=T::x;
  struct bar{static int x;};
  static int f(){return 666;}
  int bar::x=f();

  #endif

  int main()
  {
    std::cout<<"bar::x: "<<bar::x<<std::endl;
    std::cout<<"foo<bar>::x: "<<foo<bar>::x<<std::endl;
  }

Using GCC in Cygwin the output is the same for both CASE1 and CASE2:

  bar::x: 666
  foo<bar>::x: 666

Using MSVC++ 8.0 I observed a light-shedding behavior: When compiling with a
fresh project, the output is the same for CASE1 and CASE2 and coincides with
GCC:

  bar::x: 666
  foo<bar>::x: 666

But after that I changed the code to the following:

  #elif defined(CASE2)

  template<typename T>struct foo{static int x;};
  template<typename T>int foo<T>::x=T::x;
  struct bar{static int x;};
  static int x=foo<bar>::x; // NEW LINE
  static int f(){return 666;}
  int bar::x=f();

 #endif

This forces foo<bar>::x evaluation to be done at a prior monent and the
result is (for CASE2):

  bar::x: 666
  foo<bar>::x: 0

Now, the funny thing is that if I revert to the original code (i.e. I delete
the line comented as // NEW LINE) then MSVC++ 8.0 outputs the following
both for CASE1 and CASE2

  bar::x: 666
  foo<bar>::x: 0

which is different than my early runs! The compiler seems to reuse some
intermediate files from prior compilations that set a particular initialization
order: confirming this hypothesis, if I clean the project and rebuild again then
we're back at the original output for both CASE1 and CASE2:

  bar::x: 666
  foo<bar>::x: 666

So, you see how one cannot actually rely on any particular initialization
order for class template statis data. The standard explicitly leaves this
initialization order unspecified (see the rest of 3.6.2).

With respect to the rest of my previous post I maintain the explanation for
the problem with pool you're having and contend that referring to
singleton_pool<...> inside fast_pool_allocators ctors is the proper fix.

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk