在C++库中双重初始化静态STL容器

gat*_*ich 7 c++ static initialization static-libraries static-order-fiasco

这里有一些关于"静态初始化顺序惨败"的好问题和答案,但我似乎已经打击了它的另一个表达,特别难看,因为它不会崩溃但是会丢失并泄漏数据.

我有一个自定义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);
};
Run Code Online (Sandbox Code Playgroud)

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");
Run Code Online (Sandbox Code Playgroud)

MyApp.cpp中:

#include "mylib.hpp"

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

int main() {
    cout << "main():" << endl;
    MyLibClass m("main");
}
Run Code Online (Sandbox Code Playgroud)

使用以下代码编译对象:

g++ -Wall -c myapp.cpp mylib.cpp
g++ myapp.o mylib.o -o myapp1
g++ mylib.o myapp.o -o myapp2
Run Code Online (Sandbox Code Playgroud)

运行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 Code Online (Sandbox Code Playgroud)

运行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
Run Code Online (Sandbox Code Playgroud)

问题是,静态向量是重新初始化的,还是在初始化之前使用的?这是预期的行为吗?

如果我把'''作为'mylib.a'(ar rcs mylib.a mylib.o),那么问题就不会发生,但可能是因为只有一个有效的命令链接到.a而且它是最后一个库,就像myapp1一样.

但是在我们的实际应用程序中,一个包含许多目标文件和一些静态(.a)库的更复杂的应用程序共享一些静态注册表,问题正在发生,到目前为止我们设法解决它的唯一方法是应用'[10.15] ]如何防止"静态初始化命令惨败"?.

(我仍在研究我们有点复杂的构建系统,看看我们是否正确连接).

Mar*_*som 4

解决初始化顺序问题的一种方法是将静态变量从全局范围移动到局部范围。

不要registry在类中使用变量,而是将其放入函数中:

vector<string> & MyLibClass::GetRegistry()
{
    static vector<string> registry;
    return registry;
}
Run Code Online (Sandbox Code Playgroud)

在您直接使用的地方registry,让它调用GetRegistry.