static变量的生存期问题
最近要写一个单例类,简单复习下C++的基础知识。
static变量是指静态的变量,不管是在全局还是局部声明的静态变量都存放于程序的全局变量区域,所以它的生命周期是从程序开始到到程序结束。但是在C和C++中,其初始化时机又有区别,具体结论如下:
C
全局变量 | 文件域的静态变量 | 静态局部变量 | |
---|---|---|---|
初始化 | 编译期初始化 | 编译期初始化 | 编译期初始化 |
一些细节:
-
C语言的静态变量的初始值都是在编译完成后,就会保存在编译生成的可执行文件中。所以,初始值在编译时就要计算出来,因此C语言之中无法使用变量对静态变量进行初始化,即以下写法是无法编译通过的:
int a=10; int b=a; int main(){ }
C++
全局变量 | 文件域的静态变量 | 类的静态成员变量 | 静态局部变量 | |
---|---|---|---|---|
初始化 | main执行前 | main执行前 | main执行前 | 首次执行相关代码时初始化 |
一些细节:
-
上表对C++的内建类型和自定义类型均适用
-
C++中,静态成员属于类作用域,但不属于类对象,它的生命周期和普通的静态变量一样,存在于整个程序运行期间。所以不能在类的构造函数中进行初始化
-
类的成员函数中定义的静态局部变量,该类的所有对象在调用这个成员函数时将共享这个变量
-
main执行前是什么意思?到底是编译时还是运行时呢?这里引用一下C++标准(C++11 N3690 3.6.2):
全局变量、文件域的静态变量和类的静态成员变量在main执行之前的静态初始化过程中分配内存并初始化;静态局部变量(一般为函数内的静态变量)在第一次使用时分配内存并初始化。这里的变量包含内置数据类型和自定义类型的对象
那什么是静态初始化呢?继续来看C++标准:
从语言的层面来说,全局变量的初始化可以划分为以下两个阶段:
static initialization: 静态初始化指的是用常量来对变量进行初始化,主要包括 zero initialization 和 const initialization,静态初始化在程序加载的过程中完成,对简单类型(内建类型,POD等)来说,从具体实现上看,zero initialization 的变量会被保存在 bss 段,const initialization 的变量则放在 data 段内,程序加载即可完成初始化,这和 c 语言里的全局变量初始化基本是一致的。
dynamic initialization:动态初始化主要是指需要经过函数调用才能完成的初始化,比如说:int a = foo(),或者是复杂类型(类)的初始化(需要调用构造函数)等。这些变量的初始化会在 main 函数执行前由运行时调用相应的代码从而得以进行(静态局部变量除外)
根据这段描述,结合我实验的结果来看,对于内建类型,且在代码中已经手动初始化的,则该变量及其初始化值会被保存在可执行程序的data段,在运行时对其做const initialization;未手动初始化的,则该变量会被放在可执行程序的bss段,在运行时对其做zero initialization。对于自定义类型,则变量都是放在bss段,并且在运行时做动态初始化。总结如下:
手动初始化 未手动初始化 内建类型 data段,const initialization bss段,zero initialization 自定义类型 bss段,动态初始化 bss段,动态初始化 -
C++中可以使用变量对静态变量进行初始化
-
静态变量的销毁是通过
atexit()
来管理的,在程序结束,按照构造顺序反方向进行逐个析构(对于同一个编译单元内的静态变量,构造顺序和声明顺序是一致的;不同编译单元的,构造顺序是不定的)。
参考链接
https://www.runoob.com/w3cnote/cpp-static-usage.html
https://blog.csdn.net/hueru/article/details/89504059