【发布时间】:2021-11-22 13:05:49
【问题描述】:
我正在研究两个代码段的有趣行为,这给了我意想不到的行为。
描述行为
代码段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静态 会产生预期的行为,即m的值为0。 - 如果
m、n是ints,同样的行为仍然存在
因此,意外行为是 m 没有默认初始化为 0。
讨论
我的解释
- 未注释的行
cin >> n创建了一个新线程以供执行。 - 新线程创建一个新堆栈,所有局部变量都复制到该堆栈中。
- 由于
m没有在原栈中初始化,它携带的值在新栈中是不确定的。这取决于当前堆栈的状态。但是堆栈的状态取决于原始复制堆栈的状态,而原始复制堆栈的状态又取决于输入n的值。
问题
我的解释与特征 3 是一致的。不过,我不知道如何使用单个线程来检查这一点。此外,原因可能不仅仅与堆栈相关,即使只有一个线程,行为仍然存在。你怎么看?
【问题讨论】:
-
“这是预期的,并且对应于 long long 类型的默认初始化为 0(零初始化)” - 不,它没有。如果要对原语进行零初始化,则需要明确指定它。否则,该值是不确定的。
-
这是预期的,并且对应于 long long 类型的默认初始化为 0(零初始化)的事实。 这是错误的。基本类型的默认初始化会没有初始化。另一方面,值初始化将对基本类型进行零初始化。
-
在您对
cin >> n创建一个新的执行线程的猜测中(它肯定不会),您顺便提到“m未在原始线程中初始化”。这实际上是正确的,但与您之前的误解相矛盾,即m的默认初始化应该将0分配给它。 -
尝试将
m和n的定义移出main。我想你会得到你期望的零初始化 -
感谢您的回答和澄清! StoryTeller 和 NathanOliver - 谢谢 - 我现在可以在 difference between default initialization and value initialization 上阅读。内森皮尔森 - 好点!谢谢!我需要重新整理我的线程。蒂姆 - 我希望能深入了解意外行为,而不是避免它。不过,我认为您是正确的,因为在方法中声明“静态”可以避免意外行为。
标签: c++ initialization