Singleton的静态初始化顺序

Static Initialization Order for Singletons

本文关键字:顺序 初始化 静态 Singleton      更新时间:2023-10-16

所以我读到零初始化将初始化:

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

我使用的是带有传统私有构造函数的Singleton和静态公共方法,其中有一个本地静态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()

全局变量的构造函数在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是singleton中的静态成员,否则您无法实例化它。但它在概念上没有什么区别。)

有问题的场景可能是这样的:

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

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