Порядок статической инициализации для синглетонов

Так что я читаю это для Нулевая инициализация будет инициализировать:

Каждая именованная переменная со статическим или локальным потоком хранения, которая не подлежит постоянной инициализации, перед любой другой инициализацией

Я использую одиночка с традиционным приватным конструктором и статическим публичным методом, в котором есть локальный статический одноэлементный объект, который метод будет возвращать.

Моя проблема в том, что класс также имеет статический 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()

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 (во втором).

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]