这里是cppref说,
If the initialization of a non-inline variable (since C++17) is deferred to happen after the first statement of main/thread function, it happens before the first odr-use of any variable with static/thread storage duration defined in the same translation unit as the variable to be initialized.
稍后它给出了一个延迟动态初始化的例子:
// - 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();
}
评论说:
If
a
is initialized at some point after the first statement ofmain
(which odr-uses a function defined inFile 1
, forcing its dynamic initialization to run), thenb
will be initialized prior to its use in A::A
为什么if情况会发生?难道 a.Use()
odr-use a
因此必须在该语句之前初始化 a
吗?
最佳答案
我认为您被 C++ 中的事物顺序误导了。
翻译单元(TU= 一个 .cpp 文件及其 header )在 C++ 中没有顺序。它们可以按任何顺序编译,也可以并行编译。唯一特殊的 TU 是包含 main()
的那个。 , 但即使是那个也可以随时编译和订购。
在每个翻译单元中,都有一个初始化器出现的顺序。这也是它们初始化的时间顺序,但它可能与它们在内存中的顺序不同(如果确定了这一点——严格来说 C++ 并不强制执行)。这不会导致初始化程序跨 翻译单元的顺序。它确实发生在该翻译单元的函数执行之前,因为这些函数可能依赖于初始化的对象。
翻译单元中的函数当然可以以任何顺序出现;它们的执行方式取决于您在其中编写的内容。
现在有一些东西会施加额外的排序约束。我知道您知道一些初始化程序甚至可以在 main()
之后运行。已开始。如果发生这种情况,普通规则仍然适用,即单个 TU 的初始化器必须在该 TU 中的函数之前执行。
在这种情况下,TU file1
持有 b
的(默认)初始值设定项,必须在 A::A
之前运行在同一个 TU 中。正如您正确注意到的那样,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
.如果引入循环依赖,无论哪个对象先初始化,它总是依赖于一个没有被初始化的对象。不要那样做。
关于c++ - 为什么调用成员函数不调用该对象的 ODR-USE?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49814895/