【C++】依赖初始化顺序与静态初始化
1. 什么是静态初始化
-
静态初始化:在程序开始执行
main()函数之前,对具有静态存储期的对象进行的初始化,初始化顺序不定。
动态初始化:在运行时执行的初始化,通常需要执行构造函数或计算表达式。
静态初始化对象包括:- 全局变量
- extern声明的全局变量
- 类的静态成员变量
- 命名空间作用域的变量
- 函数内的
static局部变量(在首次使用时初始化)
-
静态初始化的类型
- 常量初始化
编译期:const常量在静态初始化之前,初始化后放在可执行文件的“常量区”// 常见的常量初始化 const int global_const = 42; // 编译期常量 constexpr int global_constexpr = 100; // 编译期常量 const char* global_str = "Hello"; // 编译期常量 struct Point { int x, y; }; const Point origin = {0, 0}; // 编译期常量 - 零初始化
在编译期/链接期完成,将内存置零。// 常见的零初始化 int global_int; // 初始化为 0 double global_double; // 初始化为 0.0 int* global_ptr; // 初始化为 nullptr bool global_bool; // 初始化为 false
- 常量初始化
2. 初始化顺序未定义
定义在不同.cpp文件中的静态初始化对象,其初始化顺序未定义。
// logger.hpp
class Logger
{
public:
Logger() { /* 初始化日志系统 */ }
void log(const char* msg);
};
Logger logger; //logger定义,静态初始化
// config.hpp
class Config
{
public:
Config()
{
logger.log("Config初始化"); //依赖logger
}
};
Config config; //config定义,静态初始化,这里调用Config()构造可能会崩溃,因为Logger.hpp中的logger对象可能还会初始化
// main.cpp
extern Logger logger; // 声明
extern Config config; //声明
int main() { return 0; }
3. 解决
(1)Meyers' Singleton
// 安全:首次调用时初始化,C++11保证线程安全
Logger& getLogger() {
static Logger instance;
return instance;
}
Config& getConfig() {
static Config instance;
instance.init(getLogger()); // 保证logger已初始化
return instance;
}
或是将有依赖关系的静态初始化对象直接定义在同一个.cpp中。

浙公网安备 33010602011771号