Когда инициализируются статические члены класса C++?

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

РЕДАКТИРОВАТЬ: Единственное безопасное предположение, кажется, что все статические инициализируются до начала программы (вызов main). Так что, пока я не ссылаюсь на статику из другого кода статической инициализации, мне не о чем беспокоиться?

7 ответов

Решение

Стандарт гарантирует две вещи - что объекты, определенные в одной и той же единице перевода (обычно это означает, что файл.cpp), инициализируются в порядке их определений (не объявлений):

3.6.2

Хранилище для объектов со статической продолжительностью хранения (basic.stc.static) должно быть инициализировано нулем (dcl.init) перед любой другой инициализацией. Обнуление инициализации и инициализация с постоянным выражением вместе называются статической инициализацией; все остальные инициализации - это динамическая инициализация. Объекты типов POD (basic.types) со статической продолжительностью хранения, инициализированные с помощью константных выражений (expr.const), должны быть инициализированы перед любой динамической инициализацией. Объекты со статической длительностью хранения, определенной в области имен в одной и той же единице перевода и динамически инициализированной, должны быть инициализированы в том порядке, в котором их определение появляется в единице перевода.

Другая гарантированная вещь состоит в том, что инициализация статических объектов из модуля перевода будет выполнена перед использованием любого объекта или функции из этого модуля перевода:

Это определяется реализацией независимо от того, выполняется ли динамическая инициализация (dcl.init, class.static, class.ctor, class.expl.init) объекта области имен перед первым оператором main. Если инициализация откладывается до некоторого момента времени после первого утверждения main, она должна происходить до первого использования любой функции или объекта, определенных в той же единице перевода, что и объект, который должен быть инициализирован.

Ничего другого я не гарантировал (особенно порядок инициализации объектов, определенных в разных единицах перевода, определяется реализацией).

РЕДАКТИРОВАТЬ Как указано в комментарии Сума, также гарантируется, что они инициализируются до main введен

Они инициализируются до запуска программы (т.е. до main введен).

Когда в одном файле CPP имеется два или более определений (статических данных), они инициализируются в той последовательности, в которой они определены в файле (то, что определено ранее / выше в файле, инициализируется до следующего один).

Когда имеется два или более определений (статических данных) в нескольких файлах CPP, последовательность обработки файлов CPP не определена / зависит от реализации. Это проблема, если конструктор глобальной переменной (вызываемой перед запуском программы) ссылается на другую глобальную переменную, определенную в другом файле CPP, который еще не был создан. Тем не менее, пункт 47 " Эффективного C++" Мейерса (который называется " Убедитесь, что глобальные объекты инициализируются до того, как они используются") описывает обходной путь...

  • Определите статическую переменную в заголовочном файле (она является статической, чтобы вы могли иметь ее несколько экземпляров без жалоб компоновщика)

  • Пусть конструктор этой переменной вызовет все, что вам нужно (в частности, создайте глобальные синглеты, объявленные в заголовках)

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

Ваш окончательный вывод в Правке верен. Но проблема в том, что класс сам по себе статичен. Проще сказать, что в моем коде будут статические члены класса, которые не ссылаются на другие глобальные статические члены данных / класса, но как только вы выберете этот путь, скоро все пойдет не так. Один из подходов, который я нашел полезным на практике, состоит не в том, чтобы иметь классовые члены-статические данные, а классические методы-обертки. Эти методы могут затем держать статический объект внутри себя. Например,

TypeX* Class2::getClass1Instance()
{
    static TypeX obj1;
    return &obj1;
}

Примечание: более ранний ответ говорит:

Другая гарантированная вещь - то, что инициализация статических объектов от единицы перевода будет сделана перед использованием любого объекта или функции от этой единицы перевода

Это не совсем правильно, и стандарт здесь выводится неверно. Это может не иметь места, если функция из модуля перевода вызывается до ввода main.

Их можно инициализировать в файлах реализации (.c/cpp/cc). Не инициализируйте их в.h, так как компилятор будет жаловаться на множественные определения.

Обычно они инициализируются до main, однако порядок неизвестен, поэтому избегайте зависимостей. К ним, безусловно, можно получить доступ в функции-члене. Имейте в виду, порядок инициализации неизвестен для статических членов. Я бы предложил инкапсулировать статический член в статическую функцию, которая будет проверять, был ли этот элемент инициализирован.

Я считаю, что к нему можно получить доступ в любое время во время исполнения. Что остается неопределенным, так это порядок инициализации статических переменных.

Существует не совсем тривиальный ответ на этот вопрос, но в основном они инициализируются непосредственно перед передачей управления в точку входа (основную) вашей программы. Порядок их инициализации (насколько мне известно) не определен и может зависеть от компилятора.

РЕДАКТИРОВАТЬ: Чтобы уточнить, ваше добавленное предположение правильно. Пока вы получаете доступ к нему только после основной записи, вам не нужно беспокоиться о том, когда и как он будет инициализирован. Это будет инициализировано к тому времени.

Я думаю, что основной поток процесса будет выполнять следующие пять шагов в порядке

  1. инициализация библиотеки CRT

  2. статическая инициализация

  3. выполнение функции main()

  4. статическая унитализация

  5. униализация библиотеки CRT

Вы хотите ссылочную статику из другого статического кода инициализации? возможно следующие коды работают:

class A;
static auto_ptr<A> a(auto_ptr<A>(&GetStaticA()));
A &GetStaticA(void)
{
    static A *a = NULL; //the static basic type variables initialized with constant experession will be initialized earlier than the other static ones
    if (a == NULL)
    {
         a = new A();
         return *a;
    }
}
Другие вопросы по тегам