Каково время жизни статической переменной в функции C ++?

StackOverflow https://stackoverflow.com/questions/246564

  •  05-07-2019
  •  | 
  •  

Вопрос

Если переменная объявлена как static в области видимости функции она инициализируется только один раз и сохраняет свое значение между вызовами функции.Каков именно срок его службы?Когда вызываются его конструктор и деструктор?

void foo() 
{ 
    static string plonk = "When will I die?";
}
Это было полезно?

Решение

Срок службы функции static переменные начинаются с первого раза[0] поток программы сталкивается с объявлением, и оно заканчивается при завершении программы.Это означает, что во время выполнения должно выполняться некоторое ведение бухгалтерского учета, чтобы уничтожить его, только если он действительно был создан.

Кроме того, поскольку стандарт гласит, что деструкторы статических объектов должны запускаться в порядке, обратном завершению их построения[1], и порядок построения может зависеть от конкретного запуска программы, порядок построения должен быть принят во внимание.

Пример

struct emitter {
    string str;
    emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
    ~emitter() { cout << "Destroyed " << str << endl; }
};

void foo(bool skip_first) 
{
    if (!skip_first)
        static emitter a("in if");
    static emitter b("in foo");
}

int main(int argc, char*[])
{
    foo(argc != 2);
    if (argc == 3)
        foo(false);
}

Выходной сигнал:

C:>sample.exe
Создано в foo
Уничтожен в foo

C:>sample.exe 1
Созданный в if
Создано в foo
Уничтожен в foo
Уничтожен в случае , если

C:>sample.exe 1 2
Создано в foo
Созданный в if
Уничтожен в случае , если
Уничтожен в foo

[0] С тех пор как C++98[2] не имеет ссылки на несколько потоков, как это будет вести себя в многопоточной среде, не указано и может быть проблематичным, поскольку Родди упоминания.

[1] C++98 Раздел 3.6.3.1 [базовый.начальный.термин]

[2] В C ++ 11 статика инициализируется потокобезопасным способом, это также известно как Магическая Статика.

Другие советы

Мотти прав насчет порядка, но есть еще несколько вещей, которые следует учитывать:

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

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

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

Существующие объяснения на самом деле неполны без фактического правила из Стандарта, приведенного в разделе 6.7:

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

FWIW, Codegear C ++ Builder не уничтожается в ожидаемом порядке в соответствии со стандартом.

C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if

...это еще одна причина не полагаться на приказ об уничтожении!

Тот самый Статические переменные вступают в игру, как только начинается выполнение программы и он остается доступным до тех пор, пока не завершится выполнение программы.

Статические переменные создаются в Сегмент данных в памяти.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top