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
输入的数字。此行为的其他特征是:
- 对于
n
的不同输入值,我们在 m
中得到不同的值。
- 每次给
n
相同的值,我们在 m
中得到相同的值。
- 定义
n
或 m
static 会产生预期的行为,即 m
携带值 0。
- 如果
m
、n
是 int
s ,相同的行为仍然存在
意外的行为是 m
没有默认初始化为 0。
讨论
我的解释
- 未注释的行
cin >> n
创建了一个新的执行线程。
- 新线程创建一个新堆栈,所有局部变量都复制到该堆栈。
- 由于
m
在原栈中没有初始化,所以它携带的值在新栈中是不确定的。这取决于当前堆栈的状态。但是堆栈的状态取决于原始复制堆栈的状态,而原始复制堆栈的状态又取决于输入的值 n
.
问题
我的解释与特征3一致。不过,我不知道如何使用单线程来检查这一点。此外,原因可能不仅仅是与堆栈相关的,因此即使只有一个线程,该行为仍然存在。你怎么看?
C++ 初始化超级复杂。然而,这种情况相当简单(撇开混淆的术语;)。你是对的, m
和 n
都是默认初始化的。不过,在那之后你的解释就很不对劲了。它以
开头
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:
- 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 long
is not an array type ...]
- otherwise, no initialization is performed: the objects with automatic storage duration (and their subobjects) contain indeterminate values.
读取不确定的值是未定义的行为。添加或删除看似无关的代码行会改变输出是未定义行为的典型影响。您的代码的输出可以是任何东西。它是未定义的。
我正在研究两个代码段的一个有趣行为,它给我带来了意想不到的行为。
描述行为
代码段 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
输入的数字。此行为的其他特征是:
- 对于
n
的不同输入值,我们在m
中得到不同的值。 - 每次给
n
相同的值,我们在m
中得到相同的值。 - 定义
n
或m
static 会产生预期的行为,即m
携带值 0。 - 如果
m
、n
是int
s ,相同的行为仍然存在
意外的行为是 m
没有默认初始化为 0。
讨论
我的解释
- 未注释的行
cin >> n
创建了一个新的执行线程。 - 新线程创建一个新堆栈,所有局部变量都复制到该堆栈。
- 由于
m
在原栈中没有初始化,所以它携带的值在新栈中是不确定的。这取决于当前堆栈的状态。但是堆栈的状态取决于原始复制堆栈的状态,而原始复制堆栈的状态又取决于输入的值n
.
问题
我的解释与特征3一致。不过,我不知道如何使用单线程来检查这一点。此外,原因可能不仅仅是与堆栈相关的,因此即使只有一个线程,该行为仍然存在。你怎么看?
C++ 初始化超级复杂。然而,这种情况相当简单(撇开混淆的术语;)。你是对的, m
和 n
都是默认初始化的。不过,在那之后你的解释就很不对劲了。它以
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:
- 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 long
is not an array type ...]- otherwise, no initialization is performed: the objects with automatic storage duration (and their subobjects) contain indeterminate values.
读取不确定的值是未定义的行为。添加或删除看似无关的代码行会改变输出是未定义行为的典型影响。您的代码的输出可以是任何东西。它是未定义的。