c++ - 为什么调用成员函数不调用该对象的 ODR-USE?

标签 c++ initialization language-lawyer one-definition-rule

这里是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 of main (which odr-uses a function defined in File 1, forcing its dynamic initialization to run), then b 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取决于 bB::B取决于 a .如果引入循环依赖,无论哪个对象先初始化,它总是依赖于一个没有被初始化的对象。不要那样做。

关于c++ - 为什么调用成员函数不调用该对象的 ODR-USE?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49814895/

相关文章:

c++ - 十六进制转义序列的最大长度

c++ - 在 OpenGL 中的 3D 模型上创建 AABB

c++ - 堆上的 QCoreApplication

c++ - 如何在外部目标文件中调用重命名的符号?

Android:AudioFlinger 无法创建录音轨道,状态:-1

ios - 使用reuseIdentifier初始化UICollectionViewCell

c++ - 对迭代器的钳制是否有效

c++ - 通过 Visual C++ 中的命令选项将头文件包含到项目中的每个 .h 文件中?

c# - 使用new时的数组初始化

c++ - 为什么某些 C++ 标准库 `operator<<` 函数将其流宽度重置为 0?