C++全局初始化顺序忽略依赖关系?

str*_*ger 17 c++

我认为我的问题最好在代码中描述:

#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)

请注意,这通常不被认为是一个好的设计,并且即使这解决了初始化问题,它也不能解决最终化的顺序,所以在销毁之后应该注意不要访问单例.

  • @strager:当局部变量被声明为“static”时,就会有它的单个实例,即使该函数是内联的(即,在不同的翻译单元中单独编译),链接器也必须确保只有该变量的单个定义变量存在。 (2认同)