我无法理解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
答案 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)非联合类类型,每个非静态数据 成员和每个基类子对象都是零初始化和填充 被初始化为零位;
因此,在您的情况下,还有静态存储持续时间变量,也没有线程局部变量,因此对象foo
和b
将被默认初始化,这意味着将调用该构造函数。默认构造函数(不是用户定义的)将不会初始化成员,并且在成员中将是任意垃圾,并且此任意垃圾可能为0(感谢Jarod42在评论中指出这一点)。
并且Foo().printBar();
应该打印0,因为对象是零初始化的。
答案 2 :(得分:1)
逻辑非常简单:
答案 3 :(得分:1)
Foo foo;
此默认初始化 foo
,由于Foo
的默认构造函数很简单,因此根本无法初始化它,因此foo._bar
可以保留任何值(包括0)。
Foo()
这个值初始化临时对象,如果是普通的默认构造函数意味着零初始化,那么Foo()._bar
等于0。