c++函数中静态变量的生命周期是多少?

如果一个变量在函数的作用域中声明为static,它只初始化一次,并在函数调用之间保留其值。它的寿命到底有多长?什么时候调用它的构造函数和析构函数?

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

函数static变量的生命周期在程序流第一次遇到__abc1声明时开始,并在程序终止时结束。这意味着运行时必须执行一些簿记,以便只有在实际构造了它时才销毁它。

此外,由于标准规定静态对象的析构函数必须以完成构造__abc0的相反顺序运行,而构造的顺序可能取决于具体的程序运行,因此必须考虑构造的顺序。

例子

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);
}

输出:

< p > C:祝辞sample.exe
在foo
中创建 在foo

中销毁

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

中销毁

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

中销毁

[0]由于C + + 98[2]没有引用多线程,在多线程环境中如何表现是未指定的,并且可能会有问题,如罗迪所提到的。

[1] C + + 98 section 3.6.3.1 (basic.start.term)

[2]在c++ 11中,静态数据以线程安全的方式初始化,这也被称为< em >魔法静力学< / em >

Motti关于顺序的看法是正确的,但还有一些其他的事情需要考虑:

编译器通常使用一个隐藏标志变量来指示局部静态数据是否已经初始化,并且在函数的每个条目上都检查这个标志。显然,这对性能的影响很小,但更令人担忧的是,这个标志不能保证是线程安全的。

如果你有一个如上所述的局部静态,并且foo从多个线程调用,你可能存在竞争条件,导致plonk被错误地初始化,甚至被多次初始化。同样,在这种情况下,plonk可能会被不同的线程破坏,而不是构造它的线程。

不管标准怎么说,我对局部静态破坏的实际顺序非常谨慎,因为你可能会在不知不觉中依赖于一个静态破坏后仍然有效,这真的很难追踪。

总之,Codegear c++ Builder不会按照标准的预期顺序进行破坏。

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

... 这是另一个不依赖销毁令的原因!

现有的解释是不完整的,没有来自标准的实际规则,在6.7中找到:

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

静态变量开始发挥作用,一旦开始执行程序,它保持可用,直到程序执行结束。

静态变量在内存的数据段. xml文件中创建。