静态局部变量
局部声明的静态变量在声明处进行初始化。静态局部变量只会初始化一次,之后在此访问代码块会跳过声明。
局部变量在访问时进行初始化,如果初始化抛出了异常,则认为变量未初始化。下次访问时会再次尝试进行初始化。
|
如果静态变量初始化成功,则析构函数将会在程序退出时调用。
非局部变量
所有非局部变量的静态变量在 main 函数之前进行初始化。所有 thread_local 变量作为线程启动的一部分进行初始化。
静态初始化
编译器首先尝试对变量进行 常量初始化 ,如果失败,则将静态变量和 thread_local 变量初始化为零。
- 常量初始化一般发生在编译期,预先计算对象的表现形式并将其储存到程序文件中。 - 初始化为零的变量储存在 .bss 端中。由于是操作系统通过页表映射的方式完成初始化的,因而既不占用空间,也没有运行时开销。
动态初始化
完成静态初始化后,非局部变量的动态初始化有以下情况:
无序动态初始化。仅适用于非特化类模板的静态数据成员和变量模板。这些变量的初始化顺序时不确定的。线程可能在变量初始化之前就启动了。
有序动态初始化。所有非布局变量依据声明的顺序进行初始化,不同编译单元之间变量的初始化顺序是无序的。
如果初始化过程中发生了异常,则调用 std::terminate 。 |
早期动态初始化
如果满足以下条件,则允许在编译期执行动态初始化:
构造函数不更改先于其初始化的变量的值。
静态初始化和动态初始化生成的值相同。
延长动态初始化
动态初始化的发生时机是在主函数之前还是之后发生是由实现定义的。
析构
静态变量在初始化过程中,构造函数调用 __cxa_atexit 来注册析构函数。析构函数将会在 \__cxa_finalize 中被执行。
换句话说,静态对象的析构依赖于 atexit 函数钩子。