Подтвердить что ты не робот

Что делает статическую переменную инициализацией только один раз?

Я заметил, что если вы инициализируете статическую переменную в С++ в коде, инициализация запускается только при первом запуске функции.

Это круто, но как это реализовано? Переводит ли это на какое-то извращенное утверждение if? (если задано значение, то..)

void go( int x )
{
    static int j = x ;
    cout << ++j << endl ; // see 6, 7, 8
} 

int main()
{
    go( 5 ) ;
    go( 5 ) ;
    go( 5 ) ; 
}
4b9b3361

Ответ 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

Они инициализируются только один раз, потому что это соответствует стандарту С++. Как это происходит, полностью зависит от поставщиков компилятора. По моему опыту, локальный скрытый флаг генерируется и используется компилятором.