立即初始化变量在 C++ 中很重要

Is immediately initializing a variable important in C++

提问人:just Impartial 提问时间:7/5/2023 最后编辑:Jan Schultkejust Impartial 更新时间:7/6/2023 访问量:137

问:

我最近读了一本编程书。它说如果我们在初始化变量时没有给出值,如下例所示:

int i;
int i {0};

...那么它有时可能会导致运行时错误。但是,我不确定这是否正确。未初始化的变量会设置为随机整数吗?为什么这会导致运行时错误?

我还没有遇到过这种运行时错误。为变量提供 init 值重要吗?

C++ 变量 内存 初始化 未定义行为

评论

0赞 Alan Birtles 7/5/2023
它可能在某些调试环境中,在其他环境中可能不会,其未定义的行为可能会发生,因此任何事情都可能发生
0赞 Pepijn Kramer 7/5/2023
C++ 的公理是“不要为你不使用的东西付费”。因此,除非您提出要求,否则它不会为您初始化变量。(因为有时即使您不需要初始化,初始化也需要时间)。
0赞 DevSolar 7/5/2023
重要吗?不是靠它自己,不。它在许多情况下具有更好的性能,并且避免了以后的很多问题。这两者都是......有点重要。;-)

答:

2赞 Some programmer dude 7/5/2023 #1

在 C++ 中,默认情况下不会初始化函数作用域中的非静态变量(函数内部,也称为局部变量)或没有任何其他初始化的类成员变量。它们将具有不确定的值。以任何方式使用不确定的值都会导致未定义的行为

除非您使用的是未初始化的指针,否则不太可能发生崩溃(尽管某些浮点值可能会导致异常)。纯整数只会给你带来意想不到的结果。

综上所述,如果您计划稍后(但在使用其值之前)为它们赋值,则不必显式初始化所有局部变量。


在函数或类之外定义的变量将被初始化。将其值设置为零(或类型的相应值,即指针变为 null 指针)。

static局部变量和成员变量也将初始化值。

评论

2赞 Jan Schultke 7/5/2023
它们已初始化,但默认已初始化,因此其值不确定。如果它们根本没有初始化,那么以后也会由 UB 分配它们。这是因为赋值仅更改对象的值,但不会开始对象的生存期(联合成员除外)。
0赞 463035818_is_not_an_ai 7/5/2023 #2

是的,这本书是对的。通常建议始终在声明变量后立即初始化变量。原因是从未初始化的变量中读取会调用未定义的行为。

此代码

 int evil;
 std::cout << evil;

在调试版本中可能看起来不错。在调试版本中,编译器执行的操作超出了其需要。它可能会为您进行初始化。不过,在调试版本中,编译器的作用也比在发布版本中少:它不应用优化。它不会像在发布版本中那样分析您的代码并对其进行转换以获得更好的性能。这就是为什么上面的代码在调试版本中看起来很好,而在发布版本中可能会发生不好的事情。

假设您知道您不被允许从未初始化的变量中读取,并且您写道:

 int ok;
 ok = 42;
 std::cout << ok;

然后一切都很好。但是,通常代码看起来并不那么简单。它看起来像这样:

 int notok;
 if (some_condition) {
     notok = 42;
 } else {
     std::cout << "hello world";
 }
 std::cout << notok;

很容易意外使用尚未初始化的变量。因此,建议始终初始化它们:

 int good = 42;

评论

1赞 Jan Schultke 7/5/2023
ok不是未初始化的。它是默认初始化的。它的生命周期已经开始(这就是为什么可以稍后分配它),但它的值是不确定的。
0赞 463035818_is_not_an_ai 7/5/2023
@JanSchultke用语言律师术语来说,你是对的。通俗地说,恕我直言,称其为uninitiliazed是可以的。它被初始化并且不确定的事实是 C++ 初始化的一个怪癖。请注意,即使是核心指南也说“初始化之前”,即使正式初始化 isocpp.github.io/CppCoreGuidelines/......
0赞 463035818_is_not_an_ai 7/5/2023
@JanSchultke有时,在不进行糟糕的简化的情况下向初学者解释是一种走钢丝的行为。恕我直言,这个还好,ymmv
0赞 Jan Schultke 7/5/2023
我认为在简化到不正确的地步时,至少有必要添加一个脚注并加以澄清。用“不确定值”或“垃圾值”来解释它并不比用“未初始化”来解释难多少。
0赞 just Impartial 7/6/2023 #3

感谢您上面的回复。我写了一些代码,并在我的计算机(linux 6.2.0-24-generic)中以不同的优化级别运行测试。结果如下:

❯ g++ varinit.cpp -o varinito3 -O3
 g++ varinit.cpp -o varinito2 -O2
 g++ varinit.cpp -o varinito1 -O1
 g++ varinit.cpp -o varinito0 -O0
❯ ./varinito3
0
❯ ./varinito2
0
❯ ./varinito1
0
❯ ./varinito0
32766
❯ icpx varinit.cpp
❯ ./a.out
-1884400440

我注意到在优化构建 (G++) 中,int 变量将默认初始化为零,但在无优化编译中,默认值为随机常量(运行它时不会随时间变化)。此外,在英特尔 cpp 编译器 (icpx) 中,该值是随机的,但每次编译时都会发生变化。

评论

0赞 starball 7/6/2023
这是问题的答案吗?