Порядок статической инициализации для синглетонов - PullRequest
0 голосов
/ 20 декабря 2018

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

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

Я использую 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 голосов
/ 21 декабря 2018

Конструктор для глобальных переменных выполняется до начала 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 (во втором).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...