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

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

void foo() 
{ 
    static string plonk = "When will I die?";
}

Ответ 1

Время жизни 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
Уничтожено в Фу

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

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

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

[1] С++ 98 раздел 3.6.3.1 [basic.start.term]

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

Ответ 2

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

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

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

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

Ответ 3

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

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

Ответ 4

FWIW, Codegear С++ Builder не разрушает ожидаемый порядок в соответствии со стандартом.

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

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

Ответ 5

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

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