考虑以下示例:
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
编译器才能保证线程安全。
总结
保证是:-
- 同一编译单元中的静态变量从上到下进行初始化。
- 静态是单线程初始化的。
- singleton 已经定义了构造顺序。但不一定是线程安全的。
保证不是:-
- 同时初始化所有对象。
- 静态初始化有一个工作运行时。
在调用 main 之前,您的静态和 C/C++ 运行时都在引导。您的代码和运行时之间也会出现构造顺序问题,因此您可能会使用复杂的构造函数构造一些项目,这些构造函数依赖于不可用的服务。
关于c++ - 何时使用外部链接初始化全局常量不受静态初始化顺序惨败的影响?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35628686/