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

2024-04-20

Here in cppref http://en.cppreference.com/w/cpp/language/initialization says,

如果非内联变量 (C++17 起) 的初始化推迟到主/线程函数的第一条语句之后进行,它发生在第一次 ODR 使用之前与要初始化的变量在同一转换单元中定义的具有静态/线程存储持续时间的任何变量。

随后给出了延迟动态初始化的示例:

// - 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在第一个语句之后的某个时刻初始化main(其中 odr-使用定义在File 1,强制其动态初始化运行),然后b将在 A::A 中使用之前进行初始化

为什么可以if情况发生?没有a.Use()网上争议解决使用a thus a必须在该语句之前初始化吗?


我认为你被 C++ 中的事物顺序误导了。

翻译单元(TU = 一个 .cpp 文件及其标头)在 C++ 中没有顺序。它们可以按任何顺序编译,但也可以并行编译。唯一特殊的 TU 是包含main(),但即使这样,也可以随时按顺序编译。

在每个翻译单元中,初始值设定项都有一个出现的顺序。这也是它们初始化的时间顺序,但可能与它们在内存中的顺序不同(如果确定的话 - 严格来说,C++ 并不强制执行)。这不会导致初始化程序的顺序across翻译单位。它does发生在执行该翻译单元的函数之前,因为这些函数可能依赖于初始化的对象。

翻译单元中的函数当然可以以任何顺序出现;它们的执行方式取决于您在其中写入的内容。

现在有一些事情施加了额外的排序限制。我知道您知道某些初始化程序甚至可以在之后运行main()已开始。如果发生这种情况,普通规则仍然适用,即单个 TU 的初始化程序必须在该 TU 中的函数之前执行。

在这种情况下,TUfile1保存(默认)初始值设定项b,必须先运行A::A在同一个 TU 中。正如您正确注意到的那样,a.Use必须在初始化之后发生a。这需要A::A.

因此,我们有以下顺序关系(其中< means precedes)

b < A::A
A::A < a
a < a.Use

因此传递性地

b < a.Use

正如您所看到的,使用起来很安全a.c in a.Use因为订单A::A < a.Use也成立。

You can遇到问题,如果你做A::A取决于b and B::B取决于a。如果引入循环依赖,则无论哪个对象先初始化,它总是依赖于尚未初始化的对象。不要那样做。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么调用成员函数不会调用该对象的 ODR-USE? 的相关文章

  • c++11 正则表达式比 python 慢

    嗨我想了解为什么以下代码使用正则表达式进行分割字符串分割 include
  • 中间件 API 的最佳实践是什么? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我们正在开发一个中间件 SDK 采用 C 和 Java 语言 供游戏开发人员 动画软件开发人员 阿凡达开
  • 同步执行异步函数

    我对此主题进行了大量搜索 并且阅读了本网站上有关此主题的大部分帖子 但是我仍然感到困惑 我需要一个直接的答案 这是我的情况 我有一个已建立的 Winform 应用程序 但无法使其全部 异步 我现在被迫使用一个全部编写为异步函数的外部库 在我
  • C++ 模板中的名称查找

    我有一些 C 代码 如果没有 fpermissive 选项 就无法再编译 这是我无法分享的专有代码 但我认为我已经能够提取一个简单的测试用例来演示该问题 这是 g 的输出 template eg cpp In instantiation o
  • asp.net c# 将数据集中的数据转换为电子邮件正文?

    从数据集到电子邮件正文的最佳方式是什么 我有一个 net 控制台应用程序 用于根据存储过程的结果发送电子邮件通知 并且想知道如何最好地从 SQL 数据转到电子邮件正文 带有颜色和字体的 html 正文是最好的 但纯文本也可以 thanks
  • CMake 和 Visual Studio:如何获得快速、安静的命令行构建?

    我有一个 cmake 项目 它成功地完成了我想要的一切 但我有大约 100 个文件 当我只需要重新编译一个文件时 我厌倦了每次看到生成的巨大输出 每个文件 30 行 明确地说 我正在编译cmake build 得到这个结果 我需要传递给编译
  • 如何在 MFC 中调整对话框大小时移动控件?

    我已经在 MFC 中创建了对话框视图 从下图中可以清楚地看到 如滑块控件和编辑框等 当我调整对话框大小时 这些控件不会移动 在此输入图像描述 https i stack imgur com 7OxAK jpg 我想移动控件以适应对话框 但不
  • 泛型与接口的实际优势

    在这种情况下 使用泛型与接口的实际优势是什么 void MyMethod IFoo f void MyMethod
  • 将列表(对象)转换为列表(字符串)

    有没有办法转换List of Object to a List of String 在 c 或 vb net 中而不迭代所有项目 幕后迭代很好 我只想要简洁的代码 Update 最好的方法可能就是进行新的选择 myList Select f
  • 具有多重继承的类的 sizeof

    首先 我知道 sizeof 取决于机器和编译器的实现 我使用的是 Windows 8 1 x64 gcc 5 3 0 没有标志传递给编译器 我从大学讲座中得到了以下代码 include
  • 以标准用户身份打开默认浏览器 (C++)

    我目前正在使用 ShellExecute 打开 在用户浏览器中打开 URL 但在 Win7 和 Vista 中遇到了一些麻烦 因为该程序作为服务运行提升 当 ShellExecute 打开浏览器时 它似乎读取 本地管理员 配置文件而不是用户
  • 获取给定EntityType的导航属性

    我在用VS2010 EF4 0 需要如下功能 private string GetNaviProps Type entityType eg typeof Employee NorthwindEntities en new Northwind
  • 如何附加到 xml

    我有这个xml
  • 从窗口内容截取屏幕截图(无边框)

    我正在寻找有关如何使用 C 将表单内容保存在位图中的解决方案 我已经尝试过使用 DrawToBitmap 但它捕获了所有带边框的窗口 这就是这段代码的结果 public static Bitmap TakeDialogScreenshot
  • 枚举器上的 [[maybe_unused]]

    查看规格 maybe unused http en cppreference com w cpp language attributes 它指出 出现在类 typedef 变量 非静态数据成员 函数 枚举或枚举器的声明中 如果编译器对未使用
  • 在 ncurses 中使用退格键

    我设置了一个简单的 ncurses 程序 它使用 getch 一次读取一个字符并将它们复制到缓冲区中 我遇到的问题是检测到按下退格键 这是相关代码 while buffer i c getch EOF i if c n break else
  • 如何用C++解析复杂的字符串?

    我试图弄清楚如何使用 解析这个字符串sstream 和C 其格式为 string int int 我需要能够将包含 IP 地址的字符串的第一部分分配给 std string 以下是该字符串的示例 std string 127 0 0 1 1
  • 为什么 std::ranges::filter_view 对象必须是非常量才能查询其元素?

    include
  • 在类中使用 std::chrono::high_resolution_clock 播种 std::mt19937 的正确方法是什么?

    首先 大家好 这是我在这里提出的第一个问题 所以我希望我没有搞砸 在写这篇文章之前我用谷歌搜索了很多 我对编码 C 很陌生 我正在自学 考虑到有人告诉我 只为任何随机引擎播种一次是一个很好的做法 我在这里可能是错的 什么是正确 最佳 更有效
  • 如何向 ItemsControl 中的 WPF 按钮添加相同的命令

    如何将命令添加到 wpf 按钮 该按钮是ItemsControl并正在修改ItemsSource itself 这是我的 XAML

随机推荐