我偶然发现了一个问题。
突然间,我正在处理的项目停止了工作。我正在使用Xcode 5.1.1(LLVM 3.4,clang 5.1)。问题是大多数静态变量在启动时都不会被初始化。
我没有改变任何可能导致这个问题的事情,但我很想知道是什么导致了这个问题,并且可能解决了这个问题。
我在谈论简单的情况,例如:
// File.h
class MyClass {
static std::vector<MyObject*> data;
}
// File.cpp
std::vector<MyObject*> MyClass::data;
通过运行程序,我在尝试向向量添加元素时得到一个长度异常,以实现它的大小只是一个垃圾值。这种情况发生在其他文件中的其他静态字段,没有明显的原因。代码本身不是用作库,而是按原样编译,到目前为止它完美无缺。
编辑:构建发布方案并没有显示问题,只是为了增加更多的不可预测性。
编辑:事情甚至比我预期的还要怪。我手动初始化的另一个静态变量也不起作用。违规代码如下:// .h
class MyClass {
static MyClass* i;
public:
static void init();
static MyClass* getInstance();
}
// .cpp
MyClass* MyClass::i;
void MyClass::init() { i = new MyClass(); }
MyClass* getInstance() { return i; }
现在,如果我在调用i
之后看init()
的值,并且第一次使用getInstance()
时,我会得到两个不同的地址:
(lldb) p MyClass::i
(MyClass *) $0 = 0x09e36a50
(lldb) p MyClass::i
(MyClass *) $1 = 0x00620000
我不知道这是怎么回事,因为(init()
)只被调用一次(和之前(getInstance()`)
答案 0 :(得分:1)
当您在不同的翻译单元中声明静态范围的对象时,它们的相对构造顺序是未指定的。
例如,如果您尝试使用MyClass :: Data作为构造函数的一部分来运行某些其他静态作用域对象,则在某些其他翻译单元中,未指定是否要在其他静态范围的对象构造函数之前或之后构造MyClass :: Data。如果调用访问MyClass :: Data的代码,并且尚未构造MyClass :: Data,那么这显然是未定义的行为。
在大多数常见的C ++实现中,构造的顺序取决于链接器将最终可执行文件拼凑在一起的作用;现在,对整个应用程序的各种更改完全有可能导致链接器以不同的顺序将不同的对象模块拼接在一起,并更改静态范围对象的相对构造顺序。
许多实现提供特定于实现的机制来控制静态范围对象的构造/初始化顺序。例如,gcc有init_priority
属性可用于控制此属性,请参阅https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html