C ++函数中静态variables的生命周期是什么?
如果一个variables在一个函数的作用域中被声明为static
,那么它只被初始化一次,并在函数调用之间保留它的值。 它的一生到底是什么? 它的构造函数和析构函数何时被调用?
void foo() { static string plonk = "When will I die?"; }
PS对于那些想知道我为什么问这个问题的人是否已经知道了答案?
函数static
variables的生存期从程序stream遇到声明的第一次[0]开始,在程序结束时结束。 这意味着运行时必须执行一些logging,以便只有在实际构build时才能将其破坏。
此外,由于该标准指出,静态对象的析构函数必须按照与其构造完成相反的顺序运行[1],并且构build顺序可能取决于具体的程序运行,所以必须考虑构build顺序。
例
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中创build
毁于富C:> sample.exe 1
在if中创build
在foo中创build
毁于富
如果被摧毁C:> sample.exe 1 2
在foo中创build
在if中创build
如果被摧毁
毁于富
由于C ++ 98 [2]没有引用多个线程,所以在multithreading环境中这种行为是没有规定的,并且可能是Roddy提到的问题。
[1]
C ++ 98第3.6.3.1
节[basic.start.term]
[2]
在C ++ 11中,静态线程被初始化,这也被称为Magic Statics 。
Motti对订单是正确的,但还有其他一些事情需要考虑:
编译器通常使用隐藏标志variables来指示本地静态是否已经被初始化,并且在该函数的每个条目上都检查该标志。 显然这是一个小的性能打击,但更重要的是,这个标志不能保证是线程安全的。
如果你有一个如上所述的本地静态,并且从多个线程中调用“foo”,则可能会导致“plonk”被错误地或甚至多次初始化的竞态条件。 另外,在这种情况下,“plonk”可能被破坏的线程不同于构build它的线程。
尽pipe这个标准说了什么,但我会非常警惕本地静态破坏的实际顺序,因为在破坏之后,你可能不知不觉地依靠一个仍然有效的静态方法,这是很难追查的。
如果没有6.7中的标准的实际规则,现有的解释是不完整的:
在进行任何其他初始化之前,执行具有静态存储持续时间或线程存储持续时间的所有块范围variables的零初始化。 在静态存储持续时间内(如果适用的话),对块范围实体进行持续初始化,在首次input块之前执行。 允许实现在静态或线程存储持续时间内执行其他块范围variables的早期初始化,在静态或线程存储持续时间在命名空间范围内允许实现静态初始化一个variables。 否则,这样的variables是在控件第一次通过声明时被初始化的; 这样的variables在初始化完成时被认为是初始化的。 如果通过抛出exception退出初始化,则初始化不完整,因此下一次控制进入声明时将再次尝试初始化。 如果控制在variables初始化时同时进入声明,则并发执行应等待初始化完成。 如果控件在variables被初始化时recursion地重新input声明,则行为是不确定的。
FWIW,Codegear C ++ Builder不会按照标准以预期的顺序破坏。
C:\> sample.exe 1 2 Created in foo Created in if Destroyed in foo Destroyed in if
这是不依赖于破坏命令的另一个原因!