【问题标题】:What is the difference between these initializations?这些初始化有什么区别?
【发布时间】:2020-05-13 07:06:07
【问题描述】:

以前知道未初始化的成员变量是用垃圾值初始化的。

但是,如果类中存在未初始化的指针变量,则所有未初始化的成员变量都初始化为零。

我认为指针变量只是指向堆内存中的一个实例。

为什么其他变量会改变?

我不知道这些初始化之间有什么区别。

下面是我一步一步尝试的代码。

#include <iostream>

using namespace std;

class Test {
private:
    int val1;
    int val2;

public:
    void PrintValue() {
        cout << "val1: " << val1 << endl;
        cout << "val2: " << val1 << endl;
    }
};

int main() {
    Test a;
    a.PrintValue();
}

那么,结果是

val1: -858993460
val2: -858993460

在这段代码中,我添加了 'int* ptr = new int',如下所示。

#include <iostream>

using namespace std;

class Test {
private:
    int val1;
    int val2;
    int* ptr = new int;

public:
    void PrintValue() {
        cout << "val1: " << val1 << endl;
        cout << "val2: " << val1 << endl;
    }
};

int main() {
    Test a;
    a.PrintValue();
}

结果是这样的。

val1: 0
val2: 0

为什么会这样?

我正在使用 VS community 2019 并构建工具 v142。

【问题讨论】:

  • 0 怎么不是垃圾? btw uninitialized 就是 uninitialized,没有“用垃圾初始化”之类的东西
  • 未初始化的成员变量没有用垃圾值初始化。它们根本没有初始化。这就是为什么它们被称为未初始化。它们将具有上次使用时恰好在该内存中的任何值。
  • @Eric - 当场。期望未初始化的变量最终以“垃圾值”(其中“垃圾”没有得到很好的定义,但通常被解释为“不为零”)的期望必须是 C 和 C++ 开发人员中最愚蠢的现象之一。这表明那里有太多糟糕的教材(是的,我见过很多)和太多糟糕的老师
  • 必须接受这是偶然发生的,并假设它是 msvc 的实现细节,不应该被信任。可能的原因是这些位置的字节偶然表示为零(如果 msvc 保持原样离开内存)。
  • 你是在 VS 中以 debug 还是 release 模式编译?

标签: c++ initialization


【解决方案1】:

什么都没有改变。作为default initialization的效果,数据成员val1val2将被初始化为不确定值;任何使用它们都会导致 UB,一切皆有可能。

否则,什么都不做:具有自动存储持续时间的对象(及其子对象)被初始化为不确定的值。

具有自动和动态存储持续时间的非类变量的默认初始化会生成具有不确定值的对象

【讨论】:

    【解决方案2】:

    这里的区别在于,添加 int* ptr = new int 会将您的类从 POD(plain old data) 类更改为 non-POD 类。
    如果您尝试使用第一个示例

    class Test {
    public:
        int val1;
        int val2;
    
        void PrintValue() {
            cout << "val1: " << val1 << endl;
            cout << "val2: " << val1 << endl;
        }
    };
    
    int main() {
    
        Test t;
        cout << t.val1 << endl;
    }
    

    然后你会得到一个编译器错误,因为它知道你正在尝试访问未初始化的变量。

    但是,当您添加更复杂的 int* ptr = new int 时,您的类将变为非 POD,因此编译器会为您创建一个默认构造函数,它将为您初始化变量。
    因此

    class Test {
    public:
        int val1;
        int val2;
        int* ptr = new int;
        void PrintValue() {
            cout << "val1: " << val1 << endl;
            cout << "val2: " << val1 << endl;
        }
    };
    
    int main() {
    
        Test t;
        cout << t.val1 << endl;
    }
    

    这变得合法,现在可以编译 (尽管正如其他答案所指出的那样,虽然它的输出可能看起来更干净,并且不会抛出错误,但访问这些默认的初始化变量可能仍然是 UB)

    more info on POD

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-07
      • 1970-01-01
      • 2011-02-26
      • 1970-01-01
      • 1970-01-01
      • 2011-02-14
      • 1970-01-01
      • 2011-01-20
      相关资源
      最近更新 更多