内置对象/库的静态初始化顺序失败

Static initialization order fiasco for built-in objects/libraries

本文关键字:初始化 顺序 失败 静态 对象 内置      更新时间:2023-10-16

如果我有一些变量是静态初始化的(在main开始之前),我可以自由使用这些构造函数中的任何内置内容吗,比如<iostream><vector>

发生"静态初始化顺序惨败"是因为未定义静态变量(在不同的转换单元之间)的初始化顺序。

那么,如果像这样良性的东西呢

std::cout << "Hello" << std::endl;

碰巧依赖于<iostream>中的某个静态变量提前初始化?(我并不是说它有,但假设它有。)什么意思是说内置库中的这些静态变量在我自己的静态变量之前初始化?比如说"Person.cpp"之类的。

编辑:std::cout是否保证初始化?被建议作为这个问题的重复。然而,我认为我的问题范围稍宽,因为它询问任何标准内置库,而不仅仅是<iostream>

C++标准在main开始之前或main完成之后没有对程序的行为做出强有力的声明。

根据经验,我发现了许多问题,C++运行时破坏了一些对象(例如,用于管理std::mutex的资源),这在破坏复杂类型时造成了死锁。

我建议静态的采用以下模式

C++按照执行顺序在函数中创建声明为静态的对象。这留下了一个模式,它将确保对象在需要时存在。

   AnObject * AnObject::getInstance() {
       static AnObject a;
       return &a;
   }

应执行此操作以获取全局,并将在调用getInstance()时发生。

C++11以后

该代码保证是线程安全的,如果多个执行线程到达getInstance,则只有一个线程将构造对象,其余线程将等待。

C++11之前

创建此模式将用线程安全问题替换定义不清的顺序。

幸运的是,可以在main中创建一个criticalsection/mmutex primary,它可以进行仲裁。

在某些操作系统(例如InitializeCriticalSection和Windows)中,这些锁可以在main之前安全地创建为静态变量。

   AnObject * AnObject::getInstance() {
       EnterCriticalSection( &aObjectcrit );
       static AnObject a;
       LeaveCriticalSection( &aObjectcrit );
       return &a;
   }

假设您已经在中或调用此函数之前初始化了Objectcrit。

这种模式的结果是洋葱结构的一种形式,其中对象按需要的顺序被需要,当程序退出时,它们按创建时的相反顺序被销毁。

您混淆了对象(std::cout)和类型(std::vector)。前者包含在关联问题中,后者是一种类型。静态初始化适用于对象,但不适用于类型。