Что делает статическую переменную инициализацией только один раз?
Я заметил, что если вы инициализируете статическую переменную в С++ в коде, инициализация запускается только при первом запуске функции.
Это круто, но как это реализовано? Переводит ли это на какое-то извращенное утверждение if? (если задано значение, то..)
void go( int x )
{
static int j = x ;
cout << ++j << endl ; // see 6, 7, 8
}
int main()
{
go( 5 ) ;
go( 5 ) ;
go( 5 ) ;
}
Ответы
Ответ 1
Да, он обычно преобразуется в неявный оператор if
с внутренним логическим флагом. Таким образом, в самой базовой реализации ваша декларация обычно преобразуется в нечто вроде
void go( int x ) {
static int j;
static bool j_initialized;
if (!j_initialized) {
j = x;
j_initialized = true;
}
...
}
Кроме того, если ваш статический объект имеет нетривиальный деструктор, язык должен подчиняться другому правилу: такие статические объекты должны быть разрушены в обратном порядке их построения. Поскольку порядок построения известен только во время выполнения, порядок уничтожения также определяется во время выполнения. Таким образом, каждый раз, когда вы создаете локальный статический объект с нетривиальным деструктором, программа должна зарегистрировать его в каком-то линейном контейнере, который впоследствии будет использоваться для уничтожения этих объектов в правильном порядке.
Излишне говорить, что фактические данные зависят от реализации.
Стоит добавить, что когда речь идет о статических объектах "примитивных" типов (например, int
в вашем примере), инициализированных константами времени компиляции, компилятор может инициализировать этот объект при запуске. Вы никогда не заметите разницы. Однако, если вы примете более сложный пример с "непримитивным" объектом
void go( int x ) {
static std::string s = "Hello World!";
...
то вышеупомянутый подход с if
- это то, что вы должны ожидать найти в сгенерированном коде, даже когда объект инициализируется константой времени компиляции.
В вашем случае инициализатор не известен во время компиляции, а это значит, что компилятор должен задержать инициализацию и использовать неявный if
.
Ответ 2
Да, компилятор обычно генерирует скрытое логическое значение "было ли это инициализировано?" флаг и if
, который запускается каждый раз, когда функция выполняется.
Здесь есть больше материалов для чтения: Как инициализация статической переменной реализована компилятором?
Ответ 3
В то время как это действительно "какой-то извращенный, если", твист может быть больше, чем вы себе представляли...
Комментарий ZoogieZork на ответ AndreyT затрагивает важный аспект: инициализация статических локальных переменных - на некоторые компиляторы, включая GCC - , по умолчанию - потокобезопасный (параметр командной строки компилятора может отключить его). Следовательно, он использует некоторый механизм синхронизации между потоками (мьютекс или атомная операция какого-то типа), который может быть относительно медленным. Если вам будет неудобно - разумно работать - с явным использованием такой операции в вашей функции, то вы должны подумать о том, есть ли альтернатива альтернативной альтернативе ленивой инициализации переменной (т.е. Явно построить ее в потоковом режиме самостоятельно где-то только один раз). Очень немногие функции настолько чувствительны к производительности, что это имеет значение - не позволяйте этому испортить ваш день, или сделать ваш код более сложным, если ваши программы не слишком медленны, а ваш профилировщик перебирает эту область.
Ответ 4
Они инициализируются только один раз, потому что это соответствует стандарту С++. Как это происходит, полностью зависит от поставщиков компилятора. По моему опыту, локальный скрытый флаг генерируется и используется компилятором.