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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/246564/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:01:59  来源:igfitidea点击:

What is the lifetime of a static variable in a C++ function?

c++staticlifetime

提问by Motti

If a variable is declared as staticin a function's scope it is only initialized once and retains its value between function calls. What exactly is its lifetime? When do its constructor and destructor get called?

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

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

采纳答案by Motti

The lifetime of function staticvariables begins the first time[0]the program flow encounters the declaration and it ends at program termination. This means that the run-time must perform some book keeping in order to destruct it only if it was actually constructed.

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

Additionally, since the standard says that the destructors of static objects must run in the reverse order of the completion of their construction[1], and the order of construction may depend on the specific program run, the order of construction must be taken into account.

此外,由于标准规定静态对象的析构函数必须按照其构造完成的相反顺序运行[1],并且构造的顺序可能取决于具体的程序运行,因此必须考虑构造的顺序.

Example

例子

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

Output:

输出:

C:>sample.exe
Created in foo
Destroyed in foo

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

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

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

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

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

[0]Since C++98[2]has no reference to multiple threads how this will be behave in a multi-threaded environment is unspecified, and can be problematic as Roddymentions.

[0]由于C++98 [2]没有提及多线程,因此在多线程环境中这将如何表现是未指定的,并且如Roddy提到的那样可能会出现问题。

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

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

[2]In C++11 statics are initialized in a thread safe way, this is also known as Magic Statics.

[2]在 C++11 中,静态以线程安全的方式初始化,这也称为Magic Statics

回答by Roddy

Motti is right about the order, but there are some other things to consider:

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

Compilers typically use a hidden flag variable to indicate if the local statics have already been initialized, and this flag is checked on every entry to the function. Obviously this is a small performance hit, but what's more of a concern is that this flag is not guaranteed to be thread-safe.

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

If you have a local static as above, and foois called from multiple threads, you may have race conditions causing plonkto be initialized incorrectly or even multiple times. Also, in this case plonkmay get destructed by a different thread than the one which constructed it.

如果你有一个如上的本地静态,并且foo被多个线程调用,你可能会遇到竞争条件,导致plonk初始化不正确甚至多次。此外,在这种情况下,plonk可能会被与构造它的线程不同的线程破坏。

Despite what the standard says, I'd be very wary of the actual order of local static destruction, because it's possible that you may unwittingly rely on a static being still valid after it's been destructed, and this is really difficult to track down.

尽管标准是这样说的,但我对局部静态破坏的实际顺序非常谨慎,因为您可能会在不知不觉中依赖静态在被破坏后仍然有效,而这确实很难追踪。

回答by Ben Voigt

The existing explanations aren't really complete without the actual rule from the Standard, found in 6.7:

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

The zero-initialization of all block-scope variables with static storage duration or thread storage duration is performed before any other initialization takes place. Constant initialization of a block-scope entity with static storage duration, if applicable, is performed before its block is first entered. An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope. Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined.

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

回答by Roddy

FWIW, Codegear C++Builder doesn't destruct in the expected order according to the standard.

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

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

... which is another reason not to rely on the destruction order!

……这又是一个不依赖破坏令的理由!

回答by Chandra Shekhar

The Static variablesare come into play once the program execution startsand it remain available till the program execution ends.

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

The Static variables are created in the Data Segment of the Memory.

静态变量在内存数据段中创建。