C ++静态初始化顺序:添加到地图

时间:2018-02-02 08:01:19

标签: c++

我们无法确定静态对象初始化的顺序。

但这是以下示例中的问题吗?

  • 一个静态变量是地图(或其他容器)
  • 来自其他静态变量我们填充该地图

代码:

class Factory
{
public:
    static bool Register(name, func);

private:
    static map<string, func> s_map;
};

// in cpp file
map<string, func> Factory::s_map;

bool Factory::Register(name, func)
{
    s_map[name] = func;
}

和另一个cpp文件

static bool registered = Factory::Register("myType", MyTypeCreate);

当我注册更多类型时,我不依赖于容器中的顺序。但是第一次加入容器怎么样?我可以确定它已初始化为“足够”以获取第一个元素吗?

或者这是“静态初始化命令惨败”的另一个问题?

3 个答案:

答案 0 :(得分:3)

您的方案无法保证按预期工作。成功取决于链接顺序。

确保一种方法是通过(静态)函数访问地图,该函数将对象创建为静态变量,如下所示:

h file:

class Factory
{
public:
    static bool Register(name, func);

private:
    static map<string, func>& TheMap();
};

cpp文件:

map<string, func>& Factory::TheMap()
{
    static map<string, func> g_;
    return g_;
}

bool Factory::Register(name, func)
{
    TheMap()[name] = func;
}

缺点是因为开发人员难以控制静态变量的破坏顺序。在地图的情况下,这是没有问题的。但是如果静态变量相互引用,那么静态链接就会失败。变得更糟:根据我的经验,当程序结束时,与开始时相比,防止/调试崩溃要困难得多。

答案 1 :(得分:3)

懒惰,这是来自http://en.cppreference.com/的副本:

  

<强> Non-local variables

     

具有静态存储持续时间的所有非局部变量在主函数执行开始之前被初始化为程序启动的一部分(除非延迟,见下文)。

...

  

动态初始化

     

完成所有静态初始化后,在以下情况下会发生非局部变量的动态初始化:

...

  

延迟动态初始化

     

动态初始化是在主函数的第一个语句(用于静态)还是在线程的初始函数(用于线程本地)之前发生的,或者是在之后发生的延迟发生的,是实现定义的。

     

如果非内联变量的初始化延迟发生在main / thread函数的第一个语句之后,则它发生在任何变量的第一个odr-use之前,并且在同一个转换中定义了静态/线程存储持续时间unit作为要初始化的变量。

重要的部分是odr-use

  

<强> ODR用途

     

非正式地,如果一个对象的值被读取(除非它是一个编译时常量)或者被写入,它的地址被采用,或者一个引用被绑定到它上,那么它就被使用了。

由于s_map填充了Factory::Register,我在这里看不到问题。

如果地图实现非常简单,它甚至可以作为静态初始化/编译时的一部分进行初始化。

但即使初始化延迟,只要两者都在同一个翻译单元,它就会在Factory::Register中使用之前进行初始化。

但是,如果地图是在一个翻译单元中定义的,而Factory::Register是在另一个翻译单元中定义的,那么任何事情都可能发生。

答案 2 :(得分:-1)

在首次使用之前初始化静态。你应该没事。

编辑:正如所指出的,不适用于多个翻译单元。