Question

There are a few good questions and answers here around the "static initialization order fiasco", but I seem to have hit against yet another expression of it, specially ugly because it does not crash but looses and leaks data.

I have a custom C++ library and an application that links against it. There is an static STL container in the library that registers all instances of a class. Those instances happen to be static variables in the application.

As a result of the "fiasco" (I believe), we get the container filled with the application instances during application initialization, then the library gets to initialize and the container is reset (probably leaking memory), ending up only with the instances from the library.

This is how I reproduced it with simplified code:

mylib.hpp:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class MyLibClass {
    static vector<string> registry;
    string myname;
  public:
    MyLibClass(string name);
};

mylib.cpp:

#include "mylib.hpp"

vector<string> MyLibClass::registry;

MyLibClass::MyLibClass(string name)
: myname(name)
{
    registry.push_back(name);
    for(unsigned i=0; i<registry.size(); i++)
        cout << " ["<< i <<"]=" << registry[i];
    cout << endl;
}

MyLibClass l1("mylib1");
MyLibClass l2("mylib2");
MyLibClass l3("mylib3");

myapp.cpp:

#include "mylib.hpp"

MyLibClass a1("app1");
MyLibClass a2("app2");
MyLibClass a3("app3");

int main() {
    cout << "main():" << endl;
    MyLibClass m("main");
}

Compile the objects with:

g++ -Wall -c myapp.cpp mylib.cpp
g++ myapp.o mylib.o -o myapp1
g++ mylib.o myapp.o -o myapp2

Run myapp1:

$ ./myapp1
 [0]=mylib1
 [0]=mylib1 [1]=mylib2
 [0]=mylib1 [1]=mylib2 [2]=mylib3
 [0]=mylib1 [1]=mylib2 [2]=mylib3 [3]=app1
 [0]=mylib1 [1]=mylib2 [2]=mylib3 [3]=app1 [4]=app2
 [0]=mylib1 [1]=mylib2 [2]=mylib3 [3]=app1 [4]=app2 [5]=app3
main():
 [0]=mylib1 [1]=mylib2 [2]=mylib3 [3]=app1 [4]=app2 [5]=app3 [6]=main

Run myapp2:

$ ./myapp2
 [0]=app1
 [0]=app1 [1]=app2
 [0]=app1 [1]=app2 [2]=app3
 [0]=mylib1
 [0]=mylib1 [1]=mylib2
 [0]=mylib1 [1]=mylib2 [2]=mylib3
main():
 [0]=mylib1 [1]=mylib2 [2]=mylib3 [3]=main

Here comes the question, the static vector was re-initialized, or used before initialization? Is this an expected behavior?

If I 'ar' the library as 'mylib.a' (ar rcs mylib.a mylib.o), the problem does not happen, but probably because there is only one valid order to link to the .a and it is by having the library in the last place, as for myapp1 here.

But in our real application, a more complex one with many object files and a few static (.a) libraries sharing a few static registries, the problem is happening and the only way we managed to solve it so far is by applying '[10.15] How do I prevent the "static initialization order fiasco"?'.

(I am still researching in our somewhat complex build system to see if we are linking correctly).

No correct solution

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top