我认为我的问题最好在代码中描述:
#include <stdio.h>
struct Foo;
extern Foo globalFoo;
struct Foo {
Foo() {
printf("Foo::Foo()\n");
}
void add() {
printf("Foo::add()\n");
}
static int addToGlobal() {
printf("Foo::addToGlobal() START\n");
globalFoo.add();
printf("Foo::addToGlobal() END\n");
return 0;
}
};
Foo globalFoo;
int dummy = Foo::addToGlobal();
int main() {
printf("main()\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
以上打印(使用gcc 4.4.3):
Foo::Foo()
Foo::addToGlobal() START
Foo::add()
Foo::addToGlobal() END
main()
Run Code Online (Sandbox Code Playgroud)
这是我的期望,似乎合乎逻辑.
但是,当我交换以下行时:
Foo globalFoo;
int dummy = Foo::addToGlobal();
Run Code Online (Sandbox Code Playgroud)
进入这个:
int dummy = Foo::addToGlobal();
Foo globalFoo;
Run Code Online (Sandbox Code Playgroud)
该计划输出以下内容:
Foo::addToGlobal() START
Foo::add()
Foo::addToGlobal() END
Foo::Foo()
main()
Run Code Online (Sandbox Code Playgroud)
似乎使用尚未构造的实例调用实例方法Foo!像在全局范围内移动变量声明一样简单的事情会影响程序的行为,这使我相信(1)没有定义全局变量的初始化顺序和(2)全局变量的初始化顺序忽略所有依赖项.它是否正确?是否有可能确保Foo在初始化之前调用构造函数dummy?
我试图解决的问题是静态填充项目的存储库(静态实例Foo).在我目前的尝试中,我正在使用一个宏(其中包括)创建一个全局变量(在匿名命名空间中以避免名称冲突),其初始化触发静态初始化.也许我是从错误的角度解决我的问题?有更好的选择吗?谢谢.
Jam*_*lis 37
(1)没有定义全局变量的初始化顺序
单个转换单元(源文件)中的全局变量按其定义的顺序初始化.
未指定在不同翻译单元中初始化全局变量的顺序.
(2)全局变量的初始化顺序忽略所有依赖项
对.
是否有可能确保在初始化虚拟之前调用Foo的构造函数?
是的,如果之前globalFoo已定义,则它们位于同一个翻译单元中. dummy
一种选择是拥有一个指向全局实例的静态指针; 在进行任何动态初始化之前,这样的指针将被初始化为null; addToGlobal然后可以测试指针是否为空; 如果是,那么这是第一次使用全局并且addToGlobal可以创建全局Foo.
Dav*_*eas 12
按初始化顺序,请在此处阅读答案.
关于如何解决初始化问题,可以将全局推送到函数中的静态局部变量.有标准保证静态局部变量将在第一次调用函数时初始化:
class Foo {
public:
static Foo& singleton() {
static Foo instance;
return instance;
}
};
Run Code Online (Sandbox Code Playgroud)
然后您的其他全局变量将访问变量:
Foo::singleton().add();
Run Code Online (Sandbox Code Playgroud)
请注意,这通常不被认为是一个好的设计,并且即使这解决了初始化问题,它也不能解决最终化的顺序,所以在销毁之后应该注意不要访问单例.