By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,408 Members | 945 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,408 IT Pros & Developers. It's quick & easy.

Wrong static initialization order

P: 4
Hello everybody, my first message on this forum. I tried to solve my issue by reading other similar posts, but I didn't succeed. And forgive me if this mail is so long.

I'm trying to achieve the following (with incomplete succes): I want in a given namespace Parameters a list of "initializers" (which are objects derived from a simple interface that can be implemented anywhere, and are used to define which parameters the program will take at command line) to be registered before the main starts, or better, before a function parse(argv, argc) of the namespace Parameters is called (from the main). The goal is that I to have such initializers to be called in some automatic way.

The working solution:

Each initializer is a static variable (placed in the file to which the initializer belongs) derived form a virtual class "ParametersInitializer", and its constructor calls a function Parameters::registerInitializer() passing its own pointer. Inside registerInitializer I keep track of the pointers inside a simple linked list, by storing its head and tail as static variables inside Parameters.cpp. When calling parse(), and hence when every initialization went right (especially the std::map I use to store the parameters) I call some function for each registered initializer which adds the parameters.

Now, what I want is to use an object for this list. It does not work neither with std::list nor with a very simple list object I wrote. The problem seems to be the order of initialization of static variables, which I know is not defined between different files. But I assumed that whenever a static variable is accessed, it must had been previously initialized. Which seems not to be the case.

I tried to condensed my problem in the following files:
Expand|Select|Wrap|Line Numbers
  1. /********************************************************************/
  2. Parameters.h
  3. /********************************************************************/
  4. #ifndef PARAMETERS_H
  5. #define PARAMETERS_H
  6.  
  7. // This is the prototype for the Initializers to be stored at creation time
  8. // and, later on, used by parse()
  9. class ParametersInitializer {
  10. public:
  11.         ParametersInitializer();
  12.         virtual ~ParametersInitializer();
  13. };
  14.  
  15. // Namespace for parameter parsing
  16. namespace Parameters {
  17.         // Function for registering initializers in the list
  18.         void registerInitializer(ParametersInitializer * aInitializer);
  19.  
  20.         // Command line parser
  21.         void  parse(int argc, char ** argv);
  22. };
  23.  
  24. #endif
  25.  
  26. /********************************************************************/
  27. Parameters.cpp
  28. /********************************************************************/
  29. #include <iostream>
  30. #include "Parameters.h"
  31. #include "PointerList.h"
  32.  
  33. // List of the initializers
  34. static PointerList Initializers;
  35.  
  36. ParametersInitializer::ParametersInitializer()
  37. {
  38.         // I would like to register here, but then it will acces virtual function
  39.         // Parameters::registerInitializer(this);
  40. }
  41.  
  42. ParametersInitializer::~ParametersInitializer()
  43. {
  44. }
  45.  
  46. void Parameters::registerInitializer(ParametersInitializer * aInitializer)
  47. {
  48.         // Registers the initializer in the static PointerList object
  49.         Initializers.store((void *) aInitializer);
  50.         cout << "Registering. Now there are " << Initializers.size() << " registered Initializers" << endl;
  51. }
  52.  
  53. void Parameters::parse(int argc, char ** argv)
  54. {
  55.         cout << "Parsing..." << endl;
  56.         // Prints the number of registered initializers
  57.         cout << "There are " << Initializers.size() << " registered Initializers" << endl;
  58.  
  59.         // Does the parsing of argc argv, code omitted
  60. }
  61.  
  62. /********************************************************************/
  63. PointerList.h
  64. /********************************************************************/
  65. #ifndef POINTERLIST_H
  66. #define POINTERLIST_H
  67.  
  68. #include <iostream>
  69. using namespace std;
  70.  
  71. // This should store pointers in a linked list
  72. // In this example just stores the size of such list
  73.  
  74. class PointerList{
  75. public:
  76.         PointerList() : count(0)
  77.         {
  78.                 cout << "Creating a PointerList object" << endl;
  79.         }
  80.  
  81.         void store(void * pointer)
  82.         {
  83.                 count++;
  84.         }
  85.  
  86.         int size()
  87.         {
  88.                 return count;
  89.         }
  90. private:
  91.         int count;
  92. };
  93.  
  94. #endif
  95.  
  96. /********************************************************************/
  97. somefile.cpp
  98. /********************************************************************/
  99. #include <iostream>
  100. #include "Parameters.h"
  101.  
  102. using namespace std;
  103.  
  104. // Derives from ParametersInitializer
  105. class Initializer_B : public ParametersInitializer {
  106. public:
  107.         Initializer_B()
  108.         {
  109.                 cout << "Creating an object of type Initializer_B" << endl;
  110.                 Parameters::registerInitializer(this);
  111.         }
  112. };
  113.  
  114. // Three static variables, for which the constructor will be called
  115. static Initializer_B tmp1;
  116. static Initializer_B tmp2;
  117. static Initializer_B tmp3;
  118.  
  119. /********************************************************************/
  120. main.cpp
  121. /********************************************************************/
  122. #include <iostream>
  123. #include "Parameters.h"
  124.  
  125. using namespace std;
  126.  
  127. // Derives from ParametersInitializer
  128. class Initializer_A : public ParametersInitializer {
  129. public:
  130.         Initializer_A()
  131.         {
  132.                 cout << "Creating an object of type Initializer_A" << endl;
  133.                 Parameters::registerInitializer(this);
  134.         }
  135. };
  136.  
  137. // Static variable, for which the constructor will be called
  138. static Initializer_A tmp1;
  139. static Initializer_A tmp2;
  140.  
  141. // Main function
  142. int main(int argc, char ** argv)
  143. {
  144.         // Parses arguments
  145.         Parameters::parse(argc, argv);
  146.  
  147.         return EXIT_SUCCESS;
  148. }
  149.  
As you notice, in this example there are 5 static initializers: two of type Initializer_A in main.cpp and three of type Initializer_B in somefile.cpp (obviously there should be just one static variable for each derived initializer, this is just an example).

Now, if I compile these files (the compiler is gcc version 4.0.1 for Mac) and run the program, I obtain the following output:

Creating an object of type Initializer_B
Registering. Now there are 1 registered Initializers
Creating an object of type Initializer_B
Registering. Now there are 2 registered Initializers
Creating an object of type Initializer_B
Registering. Now there are 3 registered Initializers
Creating a PointerList object
Creating an object of type Initializer_A
Registering. Now there are 1 registered Initializers
Creating an object of type Initializer_A
Registering. Now there are 2 registered Initializers
Parsing...
There are 2 registered Initializers

As you can see, first the three Initializer_B static objects are created, then the static object PointerList, and finally the two Initializer_A static objects. And therefore three initializers are lost. Obviously you may have different outcomes, since the order is undefined. But I expected PointerList to be the first, since both Initializer_A and Initializer_B access the static object PointerList (from register()).

Is gcc's fault? Or is the order undefined nomatter which object access whichother? I know that the order of initialization is unspecified among different files, but I assumed that if static A uses static B, then static B will be initialized first (or in other words, that when a static object is accessed it have been already initialized).

How can I make all this working? Is the only option to manage such a list by simple static variables (with constant initializers) and directly from within Parameters.cpp?

Anoter (smaller) problem is that I have to call the function "registerInitializer" from the constructor of each derived class, because if I call it from the constructor of the base class "ParametersInitializer" (which would be a much cleaner solution), then when I access the pure virtual function he does not access those of the derived class, but the virtual ones (with a runtime errror). Any way out?

Thanks and sorry again for the long mail,
Sandro Bosio
Mar 14 '07 #1
Share this Question
Share on Google+
1 Reply


P: 4
This is an update on my own message.

First forget about the fact that I cannot register the initializer from the constructor of the base class ParametersInitializer. Indeed now I do, I don't know why I had problems with virtual functions before (but I had them), now they seem to have disappeared.

I found out that having the PointerList object as a static member of ParametersInitializer partially solves the issue. Doing so and compiling the files, one obtains the proper initialization order (which is PointerList first), probably because the compiler finds out that such a order is needed (while before the need for initialization was hidden in a call to a function).

However, the problem still remains. When Parameters.cpp is compiled in a library, which is then linked when compiling main.cpp and somefile.cpp, then again the initialization order can fail (it happens to me at least). So, the question is still valid. Can I assume that whenever I access a static object it has been previously initialized, or I cannot?

However, I found a satisfying solution, which is having as static variable a pointer to a list (std::list or any other implementation), with a constant initialization NULL, and creating the list when at the first call of registerInitializer().

Best,
Sandro
Mar 15 '07 #2

Post your reply

Sign in to post your reply or Sign up for a free account.