【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中。

posted @ 2026-02-24 13:33  仰望星河Leon  阅读(0)  评论(0)    收藏  举报