Когда инициализируются статические члены класса C++?
Кажется, нет простого ответа на этот вопрос, но есть ли какие-либо предположения, которые можно безопасно сделать о том, когда можно получить доступ к статическому полю класса?
EDIT: единственное безопасное предположение заключается в том, что все статики инициализируются до начала работы программы (вызов main). Итак, пока я не ссылаюсь на статику из другого кода статической инициализации, мне не о чем беспокоиться?
7 ответов:
стандарт гарантирует две вещи - что объекты определены в одной и той же единице перевода (обычно это означает .cpp файл) инициализируются в порядке их определения (Не заявления):
3.6.2
хранилище для объектов со статической длительностью хранения (basic.НТЦ.статический) должен быть инициализирован нулем (dcl.init) до того, как произойдет любая другая инициализация. Нулевая инициализация и инициализация с постоянным выражением являются коллективными называется статической инициализацией; все остальные инициализации являются динамической инициализацией. Объекты типов POD (basic.типы) со статической длительностью хранения, инициализированной постоянными выражениями (expr.const) должен быть инициализирован до того, как произойдет какая-либо динамическая инициализация. Объекты со статической длительностью хранения, определенные в области пространства имен в той же единице перевода и динамически инициализированные, инициализируются в том порядке, в котором их определение появляется в переводе блок.
другая гарантированная вещь заключается в том, что инициализация статических объектов из единицы перевода будет выполнена до использования любого объекта или функции из этой единицы перевода:
определяется ли реализация динамической инициализации (dcl.инит, класс.статический класс.конструктор класса.обоснуй.инит) объекта в области видимости пространства имен осуществляется до первого заявления главная. Если инициализация отложена до некоторого момента времени после первый оператор main, он должен произойти до первого использования любой функции или объекта, определенного в той же единице перевода, что и объект, который должен быть инициализирован.
ничего другого я не гарантировал (особенно порядок инициализации объектов, определенных в разных единицах перевода, определяется реализацией).
изменить Как указано в комментарии Сумы, также гарантируется, что они инициализируются до Это.
они инициализируются до запуска программы (т. е. до
mainвводится).когда в одном файле CPP есть два или более определений (статических данных), они инициализируются в последовательности, в которой они определены в файле (тот, который определен ранее/выше в файле, инициализируется до следующего).
при наличии двух или более определений (статических данных) в более чем одном файле CPP, последовательность, в которой обрабатываются файлы CPP является неопределенным / специфичным для реализации. Это проблема, если конструктор глобальной переменной (вызываемой до запуска программы) ссылается на другую глобальную переменную, определенную в другом файле CPP, который, возможно, еще не был создан. Однако, пункт 47 Майерса Эффективный C++ (который называется убедитесь, что глобальные объекты инициализируются перед их использованием) действительно описывает обходной путь ...
определить статическую переменную в файл заголовка (он статичен, поэтому вы можете иметь несколько экземпляров без жалоб компоновщика)
пусть конструктор этой переменной вызывает все, что вам нужно (в частности, построить глобальные синглеты, объявленные в заголовках)
... что он говорит, Это метод, который может быть использован в некоторых системных заголовочных файлах, например, чтобы гарантировать, что
cinглобальная переменная инициализируется даже до статических переменных' конструкторы используют его.
ваш окончательный вывод в редактировании является правильным. Но проблема заключается в самих статических классах. Проще сказать, что мой код будет иметь статические члены класса, которые не ссылаются на другие глобальные данные/ статические члены класса, но как только вы выберете этот маршрут, все скоро пойдет не так. Один подход, который я нашел полезным на практике, чтобы не иметь членов класса static data, а методы статической оболочки класса. Эти методы могут удерживать статический объект внутри себя. Для например.
TypeX* Class2::getClass1Instance() { static TypeX obj1; return &obj1; }Примечание: более ранний ответ говорит:
другая гарантированная вещь-это инициализация статических объектов от Блока перевода будет сделано перед использованием любого объекта или функция из этой единицы перевода
Это не совсем правильно, и стандарт неправильно выводится здесь. Это может быть неверно, если функция из единицы перевода вызывается до ввода main.
Я считаю, что он может быть доступен в любое время во время выполнения. Что остается неопределенным, так это порядок инициализации статических переменных.
Они могут быть инициализированы в файле реализации (.c/cpp / cc) файлы. Не инициализируйте их .ч как компилятор будет жаловаться на множественные определения.
Они обычно инициализируются перед main, однако порядок является uknown, поэтому избегайте зависимостей. Они, безусловно, могут быть доступны в функции-члене. Имейте в виду, что порядок инициализации неизвестен для статических членов. Я бы предложил инкапсулировать статический член в статическую функцию, которая будет проверять, если член был инициализирован.
на этот вопрос нет абсолютно тривиального ответа, но в основном они инициализируются непосредственно перед тем, как управление передается в точку входа (main) вашей программы. Порядок, в котором они инициализируются (насколько мне известно), не определен и может быть специфичным для компилятора.
изменить: чтобы уточнить, ваше добавленное предположение верно. Пока вы только обращаетесь к нему post main-entry, вам действительно не нужно беспокоиться о том, когда/как он инициализируется. Он будет инициализирован этим время.
Я думаю, что основной поток процесса будет выполнять следующие пять шагов в порядке
инициализация библиотеки CRT
статическая инициализация
выполнение функции main ()
статическая унификация
унификация библиотеки 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; } }
Comments