【问题标题】:Guarantee of deferred dynamic initialization of non odr-used global variable非 odr-used 全局变量延迟动态初始化的保证
【发布时间】:2018-01-18 23:47:39
【问题描述】:

考虑以下由两个TU 组成的完整程序:

// 1.cpp
bool init() { /* ... */ }
const auto _{init()};

// 2.cpp
int main() {}

问题:是否可以保证 _ 在某个时候被初始化(我不在乎何时)?

现在考虑由一个TU组成的程序:

// 1.cpp
bool init() { /* ... */ }
const auto _{init()};
int main() {}

请注意,_ 不是 odr-used

但是,在第二种情况下,main() 是否可以称为odr-used,因为它在程序运行时被调用(在某种程度上)“被实现引用”?

如果main()odr-used,这是否意味着_ 保证被初始化,即使它不是odr-used

编辑:

这就是en.cppreference.com 所说的延迟动态初始化

如果没有从给定的翻译单元中使用的变量或函数, 该翻译单元中定义的非局部变量可能永远不会 已初始化(这模拟了按需动态库的行为)

在阅读我的两个示例时,您能回答我的问题吗?

【问题讨论】:

  • “延迟动态初始化”是什么意思?我不明白为什么这里会发生任何动态或延迟的事情。

标签: c++ std c++17


【解决方案1】:

据推测,链接器的工作是在程序启动期间从所有翻译单元中整理所有具有static storage-duration的对象以进行初始化-但是,它的作用远不止于此,保证是这些对象将在 use of any function within that translation unit 之前初始化。

basic.start.static/1: 具有静态存储持续时间的变量被初始化为 程序启动的结果......

另见:

basic.stc.static/2: 如果具有静态存储持续时间的变量有初始化或 有副作用的析构函数,即使它也不会被消除 好像没用过……

【讨论】:

  • @Martin,不,你没有遗漏任何东西。这是真的。这发生在我之前使用 CppUnit 进行测试时。基本上我在不同 TU 中的测试没有在某些平台/编译器上运行,向所有测试 TU 添加一个静态变量并使用extern 修改它解决了我的问题。
  • 好的。那么我的问题的答案是什么?我很困惑。
  • @Martin,是的,如果您不调用任何函数或对某些翻译单元 X 中的任何变量进行任何交叉引用,则 X 中的静态对象可能永远不会被初始化。见Prevent Linker from optimizing startup code
  • 那么在定义 main() 的地方定义 _ 是保证 _ 被初始化的一种方式吗?
  • @Martin,在 main() 所在的翻译单元中定义它会调用 basic.start.dynamic/4:如果此类静态对象的初始化有副作用,这将提供您寻求的保证
【解决方案2】:

对象_ 保证被初始化。根据[basic.start.static]/1,

具有静态存储持续时间的变量在程序启动时被初始化。变量与 线程存储持续时间被初始化为线程执行的结果。

如果您想知道这是否只能被解读为保证会发生静态初始化,而不是保证会发生动态初始化,请参阅 [dcl.dcl]/11,

定义导致适当的存储量 保留并进行任何适当的初始化 (11.6)。

因此,初始化器{init()} 的语义所需的所有初始化都应在对象_ 上执行。

像往常一样,as-if 规则适用。如果init() 有任何可观察到的行为,则必须发生这种行为。它有任何影响可观察行为的副作用,这种副作用必须发生。

_ 未被使用的事实无关紧要。 main 的切线也无关紧要。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-17
    • 1970-01-01
    • 1970-01-01
    • 2019-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多