静态变量的生命周期是多少?

何谓静态变量

在整个代码中, 静态变量 具有特定的生命周期。即使函数被多次调用,静态变量的内存也只分配一次,并且前一次调用的值被传递到下一次函数调用。它们不保存在堆栈中,而是保存在静态存储区

#include <iostream> 
using namespace std; 
  
void myFunc() 
{  
    // 在第一次func调用中初始化静态变量
    static int i = 0; 
    cout << i << " "; 
    // 值将保留在之前的func调用中,并被带到即将到来的func调用中
    i++; 
} 
int main() 
{ 
    for (int a = 0; a <= 7; a++)     
        myFunc();
    return 0; 
}
//输出:0 1 2 3 4 5 6 7 

1. 静态存储类的本地实现

- 当静态说明符应用于函数或块时,编译器会为其创建永久存储。
- 静态局部变量仅对定义它的函数或块可见。
- 静态局部变量是在函数调用之间保留其值的局部变量。
#include <stdio.h>
void demo()
{
    static int i = 4;
    {
        static int i;
        printf(" 局部: %d ",i);
        i++;
    }
    printf("非局部 : %d\n",i);
    i++;
}

int main()
{
   demo();
   demo();
}

输出:

 局部: 0 非局部 : 4
 局部: 1 非局部 : 5

2. 静态存储类的全局实现

当静态说明符应用于全局变量或函数时,编译器使该变量或函数仅对定义它的文件已知。
静态全局变量是具有内部链接的全局变量。
这意味着即使变量是全局的,但其他文件对此一无所知。
其他文件无法直接访问或更改其内容。
#include <stdio.h>
void func_1();
int a, b = 10;
int main()
{
    func_1();
    func_1();
    return 0;
}

void func_1()
{
    int a = 1;
    static int b = 100;
    printf("a = %d\n", a);
    printf("b = %d\n\n", b);
    a++;
    b++;
}

输出:

a = 1
b = 100

a = 1
b = 101

一个疑问

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

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

函数的生命周期 static变量在程序流第一次遇到声明时开始 ,并在程序终止时结束。 这意味着运行时必须执行一些记录,以便只有在实际构建时才将其销毁。
此外,由于标准规定静态对象的析构函数必须按照其构造完成的相反顺序运行 ,而构造顺序可能取决于具体程序运行,因此必须考虑构造顺序。

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
    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

题外说明:
编译器通常使用隐藏标志变量来指示本地静态变量是否已经初始化,并且在函数的每个条目上都会检查此标志。 显然这是一个小的性能损失,但更令人担忧的是这个标志不能保证是线程安全的。
如果您有如上所述的本地静态,并且 foo从多个线程调用,你可能有竞争条件导致 plonk初始化不正确甚至多次。 此外,在这种情况下 plonk可能会被与构造它的线程不同的线程破坏。
尽管标准说了什么,但我对局部静态破坏的实际顺序非常谨慎,因为您可能会不知不觉地依赖静态在它被破坏后仍然有效,这真的很难追踪。
————————————————
1.what is the lifetime of a static variable in a c function
2.C++简单依赖注入
[参考2] 由于c++ 98没有对多线程的引用,因此在多线程环境中如何表现是未指定的,并且可能会像Roddy提到的那样有问题。
[参考3] 在c++ 11静态是以线程安全的方式初始化的,这也被称为magic static。
————————————————

posted @ 2022-10-06 14:52  ZachLi  阅读(793)  评论(0编辑  收藏  举报