【问题标题】:If a global variable is initialized twice (statically, then dynamically), which initialization starts its lifetime?如果一个全局变量被初始化两次(静态,然后是动态),哪个初始化开始它的生命周期?
【发布时间】:2021-06-15 17:48:34
【问题描述】:

灵感来自this question

我们知道具有非constexpr 初始化器的全局变量会经历两种不同的“初始化”:

  • 首先是“静态初始化”,对它们进行零初始化。
  • 二是“动态初始化”,它使用用户提供的初始化器。

哪些初始化会启动变量的生命周期? [basic.life] 出人意料地没有帮助:

对象的生命周期...开始于:...其初始化(如果有)完成

我看到了几个选项:

  1. 最后一次初始化开始生命周期。
  2. 第一次初始化开始生命周期。
  3. 每次连续初始化都会破坏现有对象并在其位置创建一个新对象。

(1) 最有意义,但它会使稍后将动态初始化的对象的静态初始化几乎无用。

(2) 会产生有趣的效果。例如。静态初始化顺序惨败突然不再是 UB(本身)。

(3) 会很奇怪。

【问题讨论】:

  • 我不认为零初始化开始了对象的生命周期。至少对于类类型。我不相信它调用任何构造函数,所以你不能保证任何不变性。我总是将其解释为零初始化只是在实际初始化发生之前将底层表示归零。
  • @FrançoisAndrieux 不管构造函数是否被调用。参见[dcl.init.general] p19:一个已完成初始化的对象被视为已构造,即使该对象是非类类型或没有调用该对象类的构造函数进行初始化。我>

标签: c++ language-lawyer


【解决方案1】:

事实上,标准是模糊的,因为没有指定引用的规则“初始化(如果有的话)是如何完成的”适用于初始化的多个阶段,每个阶段都被称为“初始化” .这为多种解释留下了空间。

此脚注(非规范性)暗示生命周期仅在动态初始化完成后才开始:

[基本生活]

在对象的生命周期开始之前但在分配对象将占用的存储空间之后26 ...

26例如,在动态初始化具有静态存储时长的对象之前([basic.start.dynamic])。

【讨论】:

  • 谢谢,这个脚注几乎没有怀疑的余地。我已经发布了an answer 基于这个问题的原始问题。
  • 来自反射器讨论的 AFAIR,在动态初始化之前无意“中断”对对象的访问。但是解释哪种初始化足以启动生命周期需要一个核心问题。
【解决方案2】:

由于另一个答案仅根据非规范性脚注提出论点,因此我将根据非规范性注释提出反驳。并不是说我相信这种解释优于其他解释,但我认为这里的标准充其量是非规范性冲突。

[basic.start.static]/3Note 2 给出了一个未指定而非未定义的行为示例,其中允许实现者(遵守[basic.start.static]/3)执行静态/线程存储持续时间变量的初始化,即使它不需要在静态初始化期间进行初始化(可能在动态初始化期间)。这里的关键是注释的示例 why obj1 的值是未指定的:即用于初始化它的对象的 可能是“完全初始化的” " 或 "仅零初始化":

[注2:因此,如果对象obj1的初始化引用了对象obj2可能需要动态 初始化并稍后在同一个翻译单元中定义,它是 未指定 使用的obj2 的值是否为 完全初始化的 obj2 (因为obj2 是静态的 初始化)或将是的值 obj2 只是 零初始化。例如,

inline double fd() { return 1.0; }
extern double d1;
double d2 = d1;     // unspecified:
                    // either statically initialized to 0.0 or
                    // dynamically initialized to 0.0 if d1 is
                    // dynamically initialized, or 1.0 otherwise
double d1 = fd();   // either initialized statically or dynamically to 1.0

——尾注]

特别是示例代码 sn-p 中的注释:

[d2] 静态初始化为0.0 如果d1 被动态初始化,则动态初始化为0.0,否则1.0

暗示“否则”的情况,即d1(动态)从“仅零初始化”d2 初始化的情况不是未定义的。

【讨论】:

    【解决方案3】:

    我想说,动态初始化开始了该对象的生命周期。由于生命周期是这样定义的属性

    [basic.life#1]

    对象或引用的生命周期是对象或引用的运行时属性。

    零初始化可以说是在编译时发生的,这就是为什么静态初始化需要一个常量表达式作为其初始化的原因,这可以在编译时进行评估。

    您引用的规范规则中的初始化可以说是指可以启动对象生命周期的所有动态初始化(在运行时)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-21
      • 1970-01-01
      • 1970-01-01
      • 2021-10-23
      • 1970-01-01
      • 1970-01-01
      • 2011-08-22
      相关资源
      最近更新 更多