什么时候初始化全局常量与外部链接安全从静态初始化顺序fiasco?

时间:2016-02-25 13:29:34

标签: c++ static-initialization

考虑以下示例:

  • tt.h声明一个带有外部链接的全局常量extern int g_TRAGIC;

  • tt.cpp定义g_TRAGIC如下const int g_TRAGIC = 0xF001;

  • my.cpp希望用它来定义自己的全局常量const int g_MAGIC = g_TRAGIC;

当我阅读iso-FAQ时,我认为这会导致静态初始化顺序失败。但是,iso-FAQ备注

  

静态初始化顺序fiasco也可以在某些情况下应用于内置/内在类型。

某些案例意味着什么?对于内置/内在类型,我们在哪些条件下保存并从SIOF发出声音,特别是常量?或者,首次使用构造成语是否必须用于具有外部链接的所有常量?

注意:在实际代码中,我无法更改g_TRAGIC的定义。

2 个答案:

答案 0 :(得分:1)

编译器可以生成不同类型的代码。

静态初始化数据段

编译器将数据部分的名称及其初始值发送到数据部分。

.data
   dw myData   6

这是在编译时初始化的,并且在程序的整个生命周期中都是安全定义的

构建数据

另一种替代方法是让编译器为变量保留一些空间,并为数据创建初始化器/构造函数,然后在main之前调用构造函数。使用析构函数(如果需要)atexit

 class CriticalSection {
      CRITICAL_SECTION m_myCS;
      public:
         CriticalSection() {
              InitializeCriticalSection( &m_myCS );
         }
         ~CriticalSection() {
              DeleteCriticalSection( & m_myCS );
         }
 } cs;

结合

某些数据可能分两个阶段进行。

 struct Data {
     bool initialized;
     void *(*pMalloc)( size_t size );
 }  FixMalloc = { true, MyMalloc };

我见过编译器(VS2013)生成的代码在静态数据中初始化initialized为true,但是创建了一个在运行时将pMalloc赋给MyMalloc的函数。 (这是因为MyMalloc没有已知的常量。)

单身方法

 SomeClass * GetSomeClass()
 {
     static SomeClass cls;
     return &cls;
 }

这是定义的顺序 - 当它被调用时,但要求完全C++11编译器是线程安全的。

摘要

保证是: -

  1. 同一编译单元中的静态从上到下进行初始化。
  2. statics初始化为单线程。
  3. 单身人士已经确定了建筑顺序。但不一定是线程安全的。
  4. 保证不是: -

    1. 同时初始化所有对象。
    2. 静态初始化具有工作运行时。
    3. 在调用main之前,你的静态和C / C ++运行时都是bootstrapping。构造问题的顺序也发生在代码和运行时之间,因此您可以构造一些具有复杂构造函数的项,这些构造函数依赖于无法使用的服务。

答案 1 :(得分:0)

进一步阅读iso-FAQ给我们一个答案。

如果您尝试通过常量函数的返回值初始化内置/内部类型,则会发生SIOF。

const int g_MAGIC = f(g_TRAGIC);