c++ - 何时使用外部链接初始化全局常量不受静态初始化顺序惨败的影响?

标签 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 说明

The static initialization order fiasco can also, in some cases, apply to built-in/intrinsic types.

一些个案例是什么意思?在哪些条件下,我们会从 SIOF 中为内置/固有类型(尤其是常量)保存和发出声音?还是必须将 Construct On First Use Idiom 用于具有外部链接的所有常量?

注意:在实际代码中我不能更改 g_TRAGIC 的定义。

最佳答案

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

静态初始化数据段

编译器将名称及其初始值发送到数据段中。

.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. 静态是单线程初始化的。
  3. singleton 已经定义了构造顺序。但不一定是线程安全的。

保证不是:-

  1. 同时初始化所有对象。
  2. 静态初始化有一个工作运行时。

在调用 main 之前,您的静态和 C/C++ 运行时都在引导。您的代码和运行时之间也会出现构造顺序问题,因此您可能会使用复杂的构造函数构造一些项目,这些构造函数依赖于不可用的服务。

关于c++ - 何时使用外部链接初始化全局常量不受静态初始化顺序惨败的影响?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35628686/

相关文章:

c++ 指向嵌套类成员函数的指针

c++ - 静态初始化时能否安全创建线程?

C++ Nifty Counter 成语;为什么?

c - 为什么在 gcc 上接受 const 限定变量作为初始值设定项?

java - 具有初始值的 Class 实例的静态数组列表

c++ - 删除自动 int 变量

c++ - 为什么大型本地数组会使我的程序崩溃,而全局数组却不会?

c++ - 来自多页 TIFF 图像的体素大小标签

c++ - 在 glutKeyboardFunc 中所做的 OpenGL 状态更改不会立即可见