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

前端之家收集整理的这篇文章主要介绍了在C库中双重初始化静态STL容器前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这里有一些关于“静态初始化顺序惨败”的好问题和答案,但我似乎已经遇到了它的另一个表达,特别难看,因为它不会崩溃但是会丢失并泄漏数据.

我有一个自定义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] How do I prevent the “static initialization order fiasco”?’.

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

解决方法

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

而不是在类中有一个注册表变量,将它放入一个函数

vector<string> & MyLibClass::GetRegistry()
{
    static vector<string> registry;
    return registry;
}

在您将直接使用注册表的地方,让它调用GetRegistry.

猜你在找的C&C++相关文章