默认初始化与零初始化

时间:2014-12-15 12:48:12

标签: c++ initialization default zero

我无法理解gcc 4.8.1或Visual Studio 2015在默认初始化与值初始化方面的行为。

我试图理解这些之间的差异并可能遇到编译器错误,这没有帮助吗?

我的问题是:有人可以解释这种行为吗?理想情况下告诉我应该发生什么。

我有两个班级:

class Foo{
    int _bar;
public:
    void printBar(){ cout << _bar << endl; }
};

class bar{
    int ent;
public:
    int getEnt(){return ent;}
};

我正在使用以下代码进行测试:

int main()
{
    Foo foo;

    foo.printBar();
    Foo().printBar();

    bar b;

    cout << b.getEnt() << endl;

    return 0;
}

在gcc和Visual Studio上我得到:

  

134514795
  0
  0

现在,如果我将测试代码更改为:

int main()
{
    Foo foo;

    foo.printBar();

    bar b;

    cout << b.getEnt() << endl;

    return 0;
}

gcc告诉我:

  

0
  0

Visual Studio给了我:

  

50790236
  51005888

4 个答案:

答案 0 :(得分:4)

默认初始化,没有用户定义的构造函数这样的类,什么都不做,给每个普通成员留下不确定的值。

值初始化将使每个成员初始化为零。

在第一种情况下,您正在打印:

  • 默认初始化Foo foo;
  • 的不确定值
  • 值初始化Foo()
  • 的零值
  • 默认初始化bar b;
  • 的不确定值

第三个恰好为零;也许是因为它重用了临时值初始化Foo的存储空间。

在第二种情况下,您将打印两个默认初始化对象的不确定值。巧合的是,它们在一个案例中没有值,而在另一个案例中没有。

两个程序都有未定义的行为,因为它们使用未初始化的值。

答案 1 :(得分:2)

n3376引用

8.5 / 11

  

如果没有为对象指定初始值设定项,则对象为   default-initialized; 如果没有执行初始化,则为一个对象   自动或动态存储持续时间具有不确定的值。 [ 注意:   具有静态或线程存储持续时间的对象是零初始化的,   见3.6.2。 - 结束说明]

8.5 / 6

  

默认初始化T类型的对象意味着:如果T是a(可能是   cv-qualified)类类型(第9节),T的默认构造函数是   调用(如果T无法访问,则初始化结果不正确   默认构造函数);

8.5 / 10

  

一个对象,其初始化程序是一组空的括号,即(),   应进行价值初始化。

8.5 / 7

  

对T类型的对象进行值初始化意味着:

     

...

     

否则,该对象被零初始化。

8.5 / 5

  

零初始化T类型的对象或引用意味着:如果T是a   (可能是cv-qualified)非联合类类型,每个非静态数据   成员和每个基类子对象都是零初始化和填充   被初始化为零位;

因此,在您的情况下,还有静态存储持续时间变量,也没有线程局部变量,因此对象foob将被默认初始化,这意味着将调用该构造函数。默认构造函数(不是用户定义的)将不会初始化成员,并且在成员中将是任意垃圾,并且此任意垃圾可能为0(感谢Jarod42在评论中指出这一点)。 并且Foo().printBar();应该打印0,因为对象是零初始化的。

答案 2 :(得分:1)

逻辑非常简单:

  1. 默认我初始化类只是默认初始化所有成员。
  2. 内置类型的默认初始化会使成员未初始化。
  3. 访问未初始化的对象会产生undefined behavior
  4. 未定义的行为可以做任何想做的事。
  5. 两个编译器都提供“正确”的结果。请注意,导致nasal demons发出也是正确的。

答案 3 :(得分:1)

Foo foo;

默认初始化 foo,由于Foo的默认构造函数很简单,因此根本无法初始化它,因此foo._bar可以保留任何值(包括0)。

Foo()

这个值初始化临时对象,如果是普通的默认构造函数意味着零初始化,那么Foo()._bar等于0。