我有以下代码:
struct B
{
//B() {}
int x;
int y;
};
void print(const B &b)
{
std::cout<<"x:"<<b.x<<std::endl;
std::cout<<"y:"<<b.y<<std::endl;
std::cout<<"--------"<<std::endl;
}
int main()
{
B b1 = B(); //init1
B b2; //init2
print(b1);
print(b2);
return 0;
}
当我启动程序(vs2008,debug)时,我有以下输出:
x:0
y:0
--------
x:-858993460
y:-858993460
--------
正如您所见,b1.x和b1.y的值为0。为什么? init1和init2之间有什么区别?
当我取消注释B构造函数时,我有以下输出:
x:-858993460
y:-858993460
--------
x:-858993460
y:-858993460
--------
有人可以解释这种行为的原因吗? Tnx提前。
答案 0 :(得分:10)
POD类型的默认构造函数用零填充它。当您明确定义自己的构造函数时,您不会初始化x
和y
并且您将获得随机值(在VS调试中,它们将填充精确值,但在发布时它们将是随机的)。 / p>
符合C ++ 03标准8.5 / 5:
&lt; ...&gt;要值初始化 T类型的对象意味着:
- 如果T是具有用户声明的构造函数(12.1)的类类型(第9节),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);
- 如果T是没有用户声明的构造函数的非联合类类型,则T的每个非静态数据成员和基类组件都是值初始化的;
- 如果T是数组类型,则每个元素都是值初始化的;
- 否则,对象零初始化。
B()
是临时值的初始化,将用于b1
的复制初始化。
在B b2
中没有为对象指定初始值设定项,因此根据C ++ 03 Standard 8.5 / 9:
如果没有为对象指定初始化程序,并且该对象属于(可能是cv限定的)非POD类类型(或其数组),则该对象应默认初始化;如果对象是const限定类型,则底层类类型应具有用户声明的默认构造函数。 否则,如果没有为非静态对象指定初始值设定项,则该对象及其子对象(如果有)具有不确定的初始值;如果对象或其任何子对象是const限定类型,则程序格式不正确。
要为b2
获取零,您可以写B b2 = {};
。
答案 1 :(得分:5)
在这两种情况下,此语句都是从值初始化的临时B
对象中定义b1和 copy-intializes 。
B b1 = B();
当B
没有用户声明的构造函数时, value-initializing 会导致B
成员的调用 value-initalized ,对于简单类型,例如int
,这意味着零初始化。
当B
具有用户声明的构造函数时, value-initializing 会尝试调用默认构造函数。如果成员x
和y
未在构造函数初始值设定项列表中列出,则它们将保持未初始化状态。
B b2;
在函数中,没有初始化器的POD类型的本地对象未初始化。当您没有为B
定义构造函数时,它是一个POD类,因此适用,b2.x
和b2.y
的值具有不确定的值。
如果对象是非POD类类型,那么它是 default-initialized ,但是如果它调用的构造函数使其成员保持未初始化状态,那么这没有区别。
答案 2 :(得分:3)
这是值初始化而不是初始化。如果你写
B b1 = B();
你得到一个带有“value-initialized”临时值的复制初始化--B()。类类型对象的值初始化调用用户定义的构造函数(如果是existant)或以其他方式对成员进行值初始化。标量类型对象的值初始化等效于零初始化。当您声明自己没有做任何事情的构造函数时,您的标量成员不会被初始化。
B b1;
是默认初始化或根本没有初始化(取决于B)。
确切的初始化规则相当复杂。请参阅C ++标准第8.5节“初始化程序”。
答案 3 :(得分:2)
基尔的解释
另一个值:-858993460是0xCCCCCCCC,这是VC调试版本中未初始化堆栈内存的默认值。
未初始化的堆内存默认为0xCDCDCDCD。当然,在发布版本中,默认内容是随机的。
现在,我必须承认,我不知道直接调用c'tor是合法的,就像你的例子一样!而且我会发誓这是非法的......
答案 4 :(得分:0)
我试过vc6和Visual Studio 2005我得到了以下结果:你能否发布反汇编代码生成,如下所示我已经发布了2005年的反汇编代码
X:-858993460
Y:-858993460
X:-858993460
Y:-858993460
B b1 = B(); //init1
0043DEDE lea ecx,[b1]
0043DEE1 call B::B (43ADD9h)
B b2; //init2
0043DEE6 lea ecx,[b2]
0043DEE9 call B::B (43ADD9h)
print(b1);
0043DEEE lea eax,[b1]
0043DEF1 push eax
0043DEF2 call print (43A302h)
0043DEF7 add esp,4
print(b2);
0043DEFA lea eax,[b2]
0043DEFD push eax
0043DEFE call print (43A302h)
0043DF03 add esp,4