什么是C ++函数中静态变量的生命周期?

如果一个变量在函数的作用域中被声明为static ,那么它只会被初始化一次,并在函数调用之间保留它的值。 它的一生究竟是什么? 它的构造函数和析构函数何时被调用?

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

PS对于那些想知道我为什么问这个问题,我是否已经知道答案的人?


函数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
在if中创建
在foo中创建
毁于富
在if中销毁

C:> sample.exe 1 2
在foo中创建
在if中创建
在if中销毁
毁于富

[0]由于C ++ 98 [2]没有提及多线程,所以在多线程环境下这种行为是没有规定的,并且可能会有问题,因为Roddy提到。

[1] C ++ 983.6.3.1节[basic.start.term]

[2]在C ++ 11中,静态线程安全地进行初始化,这也被称为Magic Statics。


Motti对订单是正确的,但还有其他一些事情需要考虑:

编译器通常使用隐藏标志变量来指示本地静态是否已经被初始化,并且在该函数的每个入口处都检查该标志。 显然这是一个小的性能问题,但更重要的是该标志不能保证是线程安全的。

如果你有一个如上所述的本地静态,并且从多个线程中调用'foo',则可能会导致竞争条件导致'plonk'被错误地或甚至多次初始化。 此外,在这种情况下,'plonk'可能会被构建它的线程破坏。

尽管该标准说了什么,但我会对本地静态破坏的实际顺序非常谨慎,因为可能无意中依赖静态在被破坏后仍然有效,并且这很难追查到。


如果没有6.7中的标准的实际规则,现有的解释并不完整:

在进行任何其他初始化之前,执行具有静态存储持续时间或线程存储持续时间的所有块范围变量的零初始化。 在第一次输入块之前执行具有静态存储持续时间的块范围实体的常量初始化(如果适用)。 允许实现在静态或线程存储持续时间内执行其他块范围变量的早期初始化,这些条件允许在静态或线程存储持续时间在命名空间范围内静态初始化一个变量。 否则,这种变量会在控件第一次通过声明时被初始化; 这种变量在其初始化完成时被认为是初始化的。 如果通过抛出异常退出初始化,则初始化未完成,因此下一次控制进入声明时将再次尝试初始化。 如果控制在变量初始化时同时进入声明,则并发执行应等待初始化完成。 如果控制在初始化变量时递归地重新输入声明,则行为是未定义的。

链接地址: http://www.djcxy.com/p/17291.html

上一篇: What is the lifetime of a static variable in a C++ function?

下一篇: How to initialize private static members in C++?