在cppref中说,
稍后提供了延迟动态初始化的示例:
// - File 1 -
#include "a.h"
#include "b.h"
B b;
A::A(){ b.Use(); }
// - File 2 -
#include "a.h"
A a;
// - File 3 -
#include "a.h"
#include "b.h"
extern A a;
extern B b;
int main() {
a.Use();
b.Use();
}
评论说:
如果出现情况,为什么会出现?
a.Use()
odr是否使用a
而不是a
必须在此语句之前初始化? 最佳答案
我认为您被C++中事物的顺序所误导。
翻译单元(TU =一个.cpp文件及其标题)在C++中没有顺序。它们可以以任何顺序编译,也可以并行编译。唯一的特殊TU是包含main()
的TU,但即使这样,也可以随时随地进行编译。
在每个翻译单元中,都有一个初始化程序出现的顺序。这也是初始化它们的时间顺序,但是可能与它们在内存中的顺序不同(如果可以确定的话-严格来说C++不会强制执行)。这不会导致跨翻译单元的初始化程序顺序。它确实在执行该转换单元的功能之前发生,因为这些功能可能依赖于初始化的对象。
当然,翻译单元中的功能可以按任何顺序出现。它们如何执行取决于您在其中编写的内容。
现在,有些事情强加了额外的排序约束。我了解您知道,即使main()
启动后,某些初始化程序仍可以运行。如果发生这种情况,那么通常的规则仍然适用,即单个TU的初始化程序必须在该TU中的函数之前执行。
在这种情况下,TU file1
保留b
的(默认)初始化程序,该初始化程序必须在同一TU中的A::A
之前运行。如您所正确指出的,a.Use
必须在a
初始化之后发生。这需要A::A
。
因此,我们具有以下顺序关系(<
表示precedes
)
b < A::A
A::A < a
a < a.Use
因此,在传递上
b < a.Use
如您所见,在
a.c
中使用a.Use
是安全的,因为A::A < a.Use
的顺序也成立。如果使
A::A
取决于b
和B::B
取决于a
,就会遇到问题。如果引入了循环依赖关系,则无论首先初始化哪个对象,它始终取决于尚未初始化的对象。不要那样做