单例的静态初始化顺序

时间:2018-12-20 20:52:13

标签: c++ static singleton static-variables zero-initialization

所以我读到Zero Initialization会初始化:

  

每个具有静态或线程本地存储持续时间的命名变量,在进行任何其他初始化之前均无需进行常量初始化

我将Singleton与传统的私有构造函数和静态公共方法一起使用,其中有一个本地静态单例对象,该方法将返回该对象。

我的问题是,该类还具有一个静态vector,该静态初始化为零,并且似乎在 之后被初始化,这意味着我无法与之交互。是否有某些东西可以控制此初始化顺序,或者只是定义了实现?


这是我的代码的简化形式:

class Foo {
    Foo(){ s_vec.push_back(13); }
public:
    static Foo& Get() {
        static Foo singleton;
        return singleton;
    }

    int Front() const { return s_vec.front(); }
    static vector<int> s_vec;
};
vector<int> Foo::s_vec;

我遇到了这个问题,因为在代码的其他地方,我正在像这样初始化一个静态全局变量,但没有得到13:static const auto element = Foo.Get().Front()

1 个答案:

答案 0 :(得分:0)

用于全局变量的构造函数在main开始之前执行,但未指定编译单元之间的顺序。

示例中的Foo构造函数仅应在调用Foo::Get后才被调用。如果您是第一次在main中调用它,则静态矢量将已经初始化。

一种情况,您可能会遇到所描述的问题,那就是在另一个全局对象的初始化代码中调用Foo::Get时,尤其是当代码在另一个编译单元中时。

但是在这样的简单测试中,必须始终首先初始化向量,并且不会出现种族:

class Foo {
    Foo() = default;
public:
    static Foo& Get() {
        static Foo singleton;
        return singleton;
    }
    static vector<int> s_vec;
};
vector<int> Foo::s_vec; // will be initialized before main

int main() {
  Foo::Get(); // --> triggers constructor call Foo::Foo
  return 0;
}

(我假设Foo::Get是单例中的静态成员,否则您无法实例化它。但是从概念上讲,这没有任何区别。)

有问题的情况可能是这样的:

// other file
struct Bar {
  Bar() { Foo::Get(); }
};
Bar bar; // global object

您无法控制Foo::s_vec(在第一个编译单元中)和bar(在第二个编译单元中)的初始化顺序。