为什么我们可以在C++中使用未初始化的变量?

Why can we use uninitialized variables in C++?

在 Java、C# 或 PHP 等编程语言中,我们不能使用未初始化的变量。这对我来说很有意义。

C++ dot com 表示未初始化的变量在第一次被赋值之前具有不确定的值。但对于整数情况,它是 0?

我注意到我们可以在不初始化的情况下使用它并且编译器没有显示错误并且代码已执行。

示例:

#include <iostream>
using namespace std;

int main()
{
    int a;
    char b;
   
    a++; // This works... No error
    cout<< a << endl; // Outputs 1
 
    // This is false but also no error...
    if(b == '0'){
      cout << "equals" << endl;
    }
 
    return 0;
}

如果我尝试用其他语言(如 C#)复制以上代码,则会出现编译错误。我在官方文档中找不到任何内容。

我非常重视你的帮助。

C++ 让你搬起石头砸自己的脚。

将整型变量初始化为 0 是一种典型形式的机器指令

REG XOR REG

如果您想将它初始化为其他东西,它的存在并不令人满意。这对于以最快为荣的语言来说是可恶的。你断言整数被初始化为零是不正确的。

在 C++ 中使用未初始化变量的行为是未定义的。

当您的代码具有未定义的行为时,一切皆有可能。

正确的代码不包含未定义的行为。使用未初始化变量的值是未定义的行为。

未定义行为的概念并不是 C++ 独有的,但在 C++ 中它比其他地方更重要,因为编写错误代码而不会出现编译器错误的机会非常多。

但是,编译器是你的朋友。用它!例如,使用 gcc -Wall -Werror 应该是您默认的 error message:

<source>: In function 'int main()':
<source>:9:6: error: 'a' is used uninitialized [-Werror=uninitialized]
    9 |     a++; // This works... No error
      |     ~^~
<source>:13:5: error: 'b' is used uninitialized [-Werror=uninitialized]
   13 |     if(b == '0'){
      |     ^~
cc1plus: all warnings being treated as errors

但是,并非所有未定义行为的情况都可以被警告捕获(可以被视为错误)。


C++ dot com states that uninitialized variables have an undetermined value until they are assigned a value for the first time. But for integer case it's 0?

正确的术语不确定。正如您在上面的编译器输出中看到的,int a; 没有区别。当任何事情都可能发生时,未定义的行为可能看起来像是正确的行为,但它必须被修复。


TL;DR: 您不能使用未初始化变量的值。编译没有错误的代码不一定是正确的。

检测或证明变量在所有情况下都未初始化使用是不可行的,甚至是不可能的。例如:

int a;
if (<complex condition>)
    a = 0;
if (<another complex condition>)
    a = 1;
++a;

是否存在两个条件都为假的情况?你不会知道,除非你对你的程序进行广泛的分析。可以传递指向变量的指针,可能涉及多线程,使分析更加困难。 因此,决定信任程序员并仅声明那些 UB。
现代编译器可以在许多使用未初始化变量的情况下发出警告,您应该始终使用最大警告级别。

没有办法将变量“标记”为未初始化,除非您在某处存储额外的信息,或者在数据类型涵盖的值范围内保留一个值。另外,对变量的每个引用都必须测试未初始化。

这一切都是完全不能接受的。


另请注意,自动变量不会隐式初始化为某个值(比如 0),因为即使未使用该变量,它也会在 run-time 处产生成本。

正如其他人所说,编译器检测变量是否未初始化并不总是可行的,在这些情况下 C 和 C++ 更喜欢性能。

不过,还有几点补充:

  • 有动态检查器可以检测您的 test-cases 是否使用了未初始化的变量。这只有在你不zero-initialize他们“以防万一”的情况下才有效。

  • 在 C++ 中,您可以混合使用语句和声明,因此

    int a,b,c; ... c=2; a=12*c; b=...;

你可以写:

...
int c=2;
int a=12*c;
int b=...;

如果您不进一步修改它们,您也可以添加 const,lambda 表达式对此也很有用。

  • 如果您确实需要表示一个可能未初始化的变量,请使用 std::optional<...>。它可以避免某些 'possibly uninitialized' 情况,并且可以检测您是否在未初始化时尝试访问它。但这是有代价的。