【发布时间】:2023-04-03 16:41:01
【问题描述】:
这里有一些关于“静态初始化顺序惨败”的好问题和答案,但我似乎遇到了它的另一种表达方式,特别难看,因为它不会崩溃但会丢失和泄漏数据。
我有一个自定义 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
问题来了,静态向量是重新初始化的,还是在初始化之前使用的?这是预期的行为吗?
如果我将库“ar”为“mylib.a”(ar rcs mylib.a mylib.o),则问题不会发生,但可能是因为只有一个有效的命令可以链接到 .a 并且它是把图书馆放在最后,就像这里的 myapp1 一样。
但在我们的实际应用程序中,一个包含许多目标文件和几个静态 (.a) 库共享几个静态注册表的更复杂的应用程序中,问题正在发生,到目前为止,我们设法解决它的唯一方法是应用'[10.15] How do I prevent the "static initialization order fiasco"?'.
(我仍在研究我们有些复杂的构建系统,看看我们是否正确链接)。
【问题讨论】:
-
顺便说一句非常好的示例代码。我希望所有问题都像这样。
标签: c++ static initialization static-libraries static-order-fiasco