Здесь есть несколько хороших вопросов и ответов о «фиаско статического порядка инициализации», но я, кажется, натолкнулся на еще одно его выражение, особенно уродливое, потому что оно не падает, а теряет и пропускает данные.
У меня есть пользовательская библиотека C ++ и приложение, которое ссылается на нее.В библиотеке есть статический контейнер STL, который регистрирует все экземпляры класса.Эти экземпляры оказываются статическими переменными в приложении.
В результате «фиаско» (я полагаю), мы получаем контейнер, заполненный экземплярами приложения во время инициализации приложения, затем библиотека получает инициализацию иконтейнер сбрасывается (возможно, происходит утечка памяти), заканчиваясь только экземплярами из библиотеки.
Вот как я воспроизвел его с упрощенным кодом:
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");
}
Компиляцияобъекты с:
g++ -Wall -c myapp.cpp mylib.cpp
g++ myapp.o mylib.o -o myapp1
g++ mylib.o myapp.o -o myapp2
Запустите 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
Запустите 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
Здесь возникает вопрос, статический вектор был-инициализирован или используется перед инициализацией?Является ли это ожидаемым поведением?
Если я "обозначаю" библиотеку как "mylib.a" (ar rcs mylib.a mylib.o), проблема не возникает, но, вероятно, потому, что естьтолько один действительный порядок для ссылки на .a, и это при наличии библиотеки на последнем месте, как для myapp1 здесь.
Но в нашем реальном приложении более сложный, с большим количеством объектных файлов и несколькимистатические (.a) библиотеки, совместно использующие несколько статических реестров, проблема возникает, и до сих пор нам удалось ее решить только путем применения '[10.15] Как предотвратить «фиаско статического порядка инициализации»?'.
(я все еще исследую нашу довольно сложную систему сборки, чтобы проверить, правильно ли мы связываемся).