考虑以下示例:
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的定义。
答案 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
编译器是线程安全的。
保证是: -
保证不是: -
在调用main之前,你的静态和C / C ++运行时都是bootstrapping。构造问题的顺序也发生在代码和运行时之间,因此您可以构造一些具有复杂构造函数的项,这些构造函数依赖于无法使用的服务。
答案 1 :(得分:0)