【问题标题】:Recursive dependency of variable and function in global scope全局范围内变量和函数的递归依赖
【发布时间】:2020-07-29 04:39:38
【问题描述】:

我正在使用我的 C++ 编译器,我注意到一个全局变量的递归依赖,并且一个函数调用没有被拒绝。示例:

#include <iostream>

int foo();

int t = foo();

int foo()
{
    std::cout << "Hello before main: " << t << "\n";
    t = 10;
    return t + 10;
}

int main()
{
  std::cout << "Hello from main.\n";
}

这个编译后的程序打印出以下内容:

Hello before main: 0
Hello from main.

因此,当我使用声明 t 时,它依赖于 foo 函数,该函数又依赖于 t。 C++ 编译器通过在赋值表达式运行之前将 t 初始化为零来打破这个循环。

这让我很惊讶。根据标准,这是正确的行为还是我在这里调用了一些未定义的行为?

【问题讨论】:

    标签: c++ initialization language-lawyer


    【解决方案1】:

    Since C++20,对象的生命周期在其初始化完成时被认为开始;在访问它导致 UB 之前。

    [basic.life]/1:

    ...T 类型的对象的生命周期开始于:

    • 获得了与 T 类型正确对齐和大小的存储,并且
    • 其初始化(如果有)已完成(包括空初始化)...

    直到 C++20,这是定义明确的行为。 Zero initialization 首先是为non-local variables 执行的。

    如non-local initialization 中所述,静态和线程局部变量that aren't constant-initialized (since C++14) 在任何其他初始化发生之前被初始化为零。如果非类非局部变量的定义没有初始化器,则默认初始化什么也不做,保持之前零初始化的结果不变。

    来自标准,[basic.start.static]/2

    如果不执行常量初始化,则具有静态存储持续时间 ([basic.stc.static]) 或线程存储持续时间 ([basic.stc.thread]) 的变量将被零初始化 ([dcl.init])。零初始化和常量初始化合称为静态初始化;所有其他初始化都是动态初始化。所有静态初始化都发生在 ([intro.races]) 任何动态初始化之前。

    【讨论】:

    • @LanguageLawyer 我不太确定,但这是否意味着t 的生命周期仅在所有初始化(包括本例的零初始化和复制初始化)完成时才开始?跨度>
    • 目前读作动态初始化完成前访问对象是UB,但IIUC认为这是缺陷。
    猜你喜欢
    • 1970-01-01
    • 2013-07-13
    • 2015-03-22
    • 1970-01-01
    • 2011-06-11
    • 1970-01-01
    • 1970-01-01
    • 2013-05-17
    • 2020-10-02
    相关资源
    最近更新 更多