【问题标题】:Initialization order of constant initialized variable with static storage duration具有静态存储持续时间的常量初始化变量的初始化顺序
【发布时间】:2020-02-17 03:04:30
【问题描述】:

基于以下代码sn-p:

const int a = 42;
const int b = a;

我们知道对这两个变量都进行了常量初始化,而常量初始化就是静态初始化。

由于未指定静态初始化的顺序(与指定顺序的动态初始化不同),这不会导致未定义的行为,就好像b 的静态初始化发生在a 之前一样,它会是读取未初始化的内存?

【问题讨论】:

  • 评论不用于扩展讨论;这个对话是moved to chat
  • “读取未初始化的内存”没有未定义的行为。如果您的意思是不确定值,那么只有具有自动和动态存储持续时间的对象才会进行 b4 初始化。

标签: c++ initialization language-lawyer static-initialization


【解决方案1】:

首先,让我们澄清一下上下文:我们正在考虑初始化具有静态存储持续时间的变量。这个初始化实际上有两个部分:静态阶段和动态阶段。静态阶段首先发生,在这个阶段变量之间没有依赖关系。初始化顺序仅对具有静态存储的变量的动态初始化很重要。

静态变量的(动态)初始化顺序通常不是未指定的。它通常在单独的翻译单元之间未指定,并且在某些情况下在单个翻译单元内也是如此。

const int a = dynamic_init();
const int b = a;

如果这些变量像示例中那样位于单个 TU 中,则指定顺序:a 首先声明,因此它首先被初始化。

const int a = 42;
const int b = a;

42 是一个常量表达式。因此a 具有常量初始化,即静态初始化(非动态)。因此初始化顺序对于这个变量并不重要。

a 也是一个常量表达式,因为a 是具有静态存储和常量初始化器的const 变量。因此b 也有非动态初始化。因此初始化顺序对于这个变量并不重要。


不影响上下文:

由于未指定静态初始化的顺序[...],这不会导致未定义的行为,就好像 b 的静态初始化发生在 a 之前一样

仅仅因为标准没有指定顺序,并不意味着实现可以为所欲为。标准说静态初始化发生,实现负责执行它。它必须选择一个按指定工作的顺序。

实际上,顺序并不重要,因为程序无法观察到它。无论实现选择如何实现,这两个变量都初始化为 42。

【讨论】:

  • 我理解静态初始化和动态初始化之间的区别,我所说的一切都是我所说的。
  • @KrystianS 好。我回答的后半部分会和你有关。
  • 反正如你所说,两者都有常量初始化,也就是静态初始化。静态初始化没有定义的顺序。因此,b 完全有可能在a 之前初始化,这将导致ba 初始化之前读取a 的值。
  • @KrystianS 为什么常量初始化会涉及读取变量?
  • 因为这正是标准定义它的方式。
【解决方案2】:

由[intro.execution]指定

这两个声明的完整表达式分别是它们的 init 声明符。根据 [intro.execution#5]

一个完整的表达式是。

  • init-declarator ([dcl.decl]) 或 mem-initializer ([class.base.init]),包括初始化器的组成表达式。

相关的初始化被认为是其完整表达式的一部分

对于初始化器,执行实体的初始化(包括评估聚合的默认成员初始化器)也被视为完整表达式的一部分。

因此,它们的评估顺序由以下定义:

与完整表达式关联的每个值计算和副作用与要评估的下一个完整表达式关联的每个值计算和副作用之前排序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-17
    • 1970-01-01
    • 2015-06-01
    • 2018-12-19
    • 1970-01-01
    • 2011-08-22
    相关资源
    最近更新 更多