2008-10-29 3 views
289

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

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

P.S. Для тех, кто хочет знать why I asked the question if I already knew the answer?

+17

Обычно я не голосую за вопросы, на которые ответчик сразу ответил сам, но этот интересен. Спасибо, что вызвали это. – 2008-10-29 12:31:33

+0

@ Мотти Линк мертв. – Zaimatsu 2015-08-26 08:25:42

+0

@ Zaimatsu ссылка все еще работает для меня. – Motti 2015-08-29 18:34:16

ответ

177

Время жизни функции 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); 
} 

Выход:

С:> SAMPLE.EXE
Созданный в Foo
разрушаемый в Foo

С:> SAMPLE.EXE 1
Созданный в случае
Созданный в Foo
Разрушенный в Foo
Разрушенный, если

С:> SAMPLE.EXE 1 2
Созданный в Foo
Созданный в случае
разрушаемый, если
разрушен в Foo

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

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

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

+2

Для простых типов без каких-либо побочных эффектов c'tor/d'tor, простая оптимизация инициализирует их так же, как и глобальные простые типы. Это позволяет избежать проблем ветвления, флага и порядка уничтожения. Это не значит, что их жизнь ничем не отличается. – 2011-10-29 01:06:05

114

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

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

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

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

8

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

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

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

9

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

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

Смежные вопросы