C++ 默认值初始化随着输入输出流的变化而变化

C++ default value initialization changes with input-output streams

我正在研究两个代码段的一个有趣行为,它给我带来了意想不到的行为。

描述行为

代码段 1:

#include <iostream>

using namespace std;

int main()
{
    long long n;
    long long m;
    
    // cin >> n;

    cout << m;

    return 0;
}

当我运行这个的时候(比如在https://www.onlinegdb.com/online_c++_compiler中),控制台打印的值(变量m里面的值)是0。这是预期的,对应的事实上 long long 类型默认初始化为 0(零初始化)。

代码段2:

#include <iostream>

using namespace std;

int main()
{
    long long n;
    long long m;
    
    cin >> n;

    cout << m;

    return 0;
}

通过取消注释 cin 的行并添加任何值,我没有得到 0,而是一个不同的值,具体取决于我为 n 输入的数字。此行为的其他特征是:

  1. 对于 n 的不同输入值,我们在 m 中得到不同的值。
  2. 每次给 n 相同的值,我们在 m 中得到相同的值。
  3. 定义 nm static 会产生预期的行为,即 m 携带值 0。
  4. 如果 mnints
  5. ,相同的行为仍然存在

意外的行为是 m 没有默认初始化为 0。

讨论

我的解释

  1. 未注释的行 cin >> n 创建了一个新的执行线程。
  2. 新线程创建一个新堆栈,所有局部变量都复制到该堆栈。
  3. 由于m在原栈中没有初始化,所以它携带的值在新栈中是不确定的。这取决于当前堆栈的状态。但是堆栈的状态取决于原始复制堆栈的状态,而原始复制堆栈的状态又取决于输入的值 n.

问题

我的解释与特征3一致。不过,我不知道如何使用单线程来检查这一点。此外,原因可能不仅仅是与堆栈相关的,因此即使只有一个线程,该行为仍然存在。你怎么看?

C++ 初始化超级复杂。然而,这种情况相当简单(撇开混淆的术语;)。你是对的, mn 都是默认初始化的。不过,在那之后你的解释就很不对劲了。它以

开头

This is expected and corresponds to the fact that the long long type has a default initialization to 0 (zero initialization).

long long int 的默认初始化是 而不是 零初始化。实际上它根本就没有初始化。来自 cppreference:

Default initialization is performed in three situations:

  1. when a variable with automatic, static, or thread-local storage duration is declared with no initializer;

[...]

The effects of default initialization are:

  • if T is a non-POD (until C++11) class type, [... long long is not a class type ...]
  • if T is an array type, [... long longis not an array type ...]
  • otherwise, no initialization is performed: the objects with automatic storage duration (and their subobjects) contain indeterminate values.

读取不确定的值是未定义的行为。添加或删除看似无关的代码行会改变输出是未定义行为的典型影响。您的代码的输出可以是任何东西。它是未定义的。