c++类成员初始化问题

时间:2022-09-09 20:13:54
class A
 { int i;}

main()
{
       A a; //这个时候a里面的i是随机值
       A *p= new A();//这个时候p里面的i是0

}


所以我可以得出这么一个结论不:
1 )在堆里面申请内存 内存里面的值是“0”值?( 
  如果1)成立的话 : 2)可是为什么看到有的人会把从堆里面申请的内存memset为0呢? 是不是没有这个必要?

3)在栈里面定义的类的变量 其成员值是随机的?


高手解答下这三个问题

19 个解决方案

#1


补充下 2) 看到有人是malloc一段内存 然后memset为0

#2


分配的地方不一样,new在堆上分配

#3


00415630  push        ebp  
00415631  mov         ebp,esp 
00415633  sub         esp,100h 
00415639  push        ebx  
0041563A  push        esi  
0041563B  push        edi  
0041563C  lea         edi,[ebp-100h] 
00415642  mov         ecx,40h 
00415647  mov         eax,0CCCCCCCCh 
0041564C  rep stos    dword ptr es:[edi] 
0041564E  mov         byte ptr [ebp-0DDh],0 
   A a; //这个时候a里面的i是随机值
  A *p= new A();//这个时候p里面的i是0
00415655  mov         dword ptr [ebp-0F8h],4 
0041565F  mov         eax,dword ptr [ebp-0F8h] 
00415665  push        eax  
00415666  call        operator new (41161Dh) 
0041566B  add         esp,4 
0041566E  mov         dword ptr [ebp-0ECh],eax 
00415674  cmp         dword ptr [ebp-0ECh],0 
0041567B  je          main+73h (4156A3h) 
0041567D  mov         ecx,dword ptr [ebp-0F8h] 
00415683  push        ecx  
00415684  push        0    
00415686  mov         edx,dword ptr [ebp-0ECh] 
0041568C  push        edx  
0041568D  call        @ILT+1860(_memset) (411749h) 
00415692  add         esp,0Ch 
00415695  mov         eax,dword ptr [ebp-0ECh] 
0041569B  mov         dword ptr [ebp-100h],eax 
004156A1  jmp         main+7Dh (4156ADh) 
004156A3  mov         dword ptr [ebp-100h],0 
004156AD  mov         ecx,dword ptr [ebp-100h] 
004156B3  mov         dword ptr [p],ecx 

#4


编译器就是这么定的,记住就行了。

#5


引用 3 楼 luciferisnotsatan 的回复:
Assembly code
00415630  push        ebp  
00415631  mov         ebp,esp 
00415633  sub         esp,100h 
00415639  push        ebx  
0041563A  push        esi  
0041563B  push        edi  
0041563C ……

学习了

#6


理论上,栈上对象也该调用默认构造函数,但这里没有。int这种内建类型默认设置为0。
同时,堆上也没有调用,只是用了个简单的memset。

#7


class A
 { 
 public:
 int i;};

int main(int argc, char *argv[])
{
00415630  push        ebp  
00415631  mov         ebp,esp 
00415633  sub         esp,10Ch 
00415639  push        ebx  
0041563A  push        esi  
0041563B  push        edi  
0041563C  lea         edi,[ebp-10Ch] 
00415642  mov         ecx,43h 
00415647  mov         eax,0CCCCCCCCh 
0041564C  rep stos    dword ptr es:[edi] 
   A a = A(); //这个时候a里面的i是随机值
0041564E  xor         eax,eax                         #eax 清0
00415650  mov         dword ptr [ebp-104h],eax 
00415656  mov         ecx,dword ptr [ebp-104h] 
0041565C  mov         dword ptr [a],ecx 
   int i = 1;
0041565F  mov         dword ptr [i],1 
  A *p= new A();//这个时候p里面的i是0
00415666  mov         dword ptr [ebp-0F8h],4 
00415670  mov         eax,dword ptr [ebp-0F8h] 
00415676  push        eax  
00415677  call        operator new (41161Dh) 
0041567C  add         esp,4 
0041567F  mov         dword ptr [ebp-0ECh],eax 
00415685  cmp         dword ptr [ebp-0ECh],0 
0041568C  je          main+84h (4156B4h) 
0041568E  mov         ecx,dword ptr [ebp-0F8h] 
00415694  push        ecx  
00415695  push        0    
00415697  mov         edx,dword ptr [ebp-0ECh] 
0041569D  push        edx  
0041569E  call        @ILT+1860(_memset) (411749h) 
004156A3  add         esp,0Ch 
004156A6  mov         eax,dword ptr [ebp-0ECh] 
004156AC  mov         dword ptr [ebp-10Ch],eax 
004156B2  jmp         main+8Eh (4156BEh) 
004156B4  mov         dword ptr [ebp-10Ch],0 
004156BE  mov         ecx,dword ptr [ebp-10Ch] 
004156C4  mov         dword ptr [p],ecx 
  printf("%d",a.i);
004156C7  mov         esi,esp 
004156C9  mov         eax,dword ptr [a] 
004156CC  push        eax  
004156CD  push        offset string "%d" (4237FCh) 
004156D2  call        dword ptr [__imp__printf (42850Ch)] 
004156D8  add         esp,8 
004156DB  cmp         esi,esp 
004156DD  call        @ILT+1290(__RTC_CheckEsp) (41150Fh)  


虽然还是没看到代码里有调默认构造函数(也没有临时对象生成),但输出就是0了。
所以你还是应该自己写构造函数。而不是听编译器由命

#8


引用 2 楼 bdmh 的回复:
分配的地方不一样,new在堆上分配

学习

#9


引用 8 楼 jiangchaomr 的回复:
引用 2 楼 bdmh 的回复:

分配的地方不一样,new在堆上分配

学习

多谢

#10


Hello * = new hello, 是堆内存分配。分配在你的数据和常量区。 Hello hello 是栈内存分配,分配在你的程序的尾巴部分。

#11



class A
{
    int i;
};


A类没有定义构造函数,因为其成员是内置类型的,所以在构造A类对象时,
语言级别上,编译器应该只为其分配空间,不对其成员做任何的初始化,
这在在栈上和堆上创建对象来讲都是一样的,语言级别上来讲,值都应该是随机的
至于楼主所说的在堆上创建对象时,空间被memset过了,这最多算是编译器的扩展,标准中并没有规定

标准中只是说了对于内置类型,支持一种特殊的构造语法,可将对象初始化为0,比如:
int *p = new int();

但是对于类类型来说,加不加最后的()都是一样的,都是调用缺省的构造函数,就像类A,其缺省的构造函数不会对其成员初始化,

楼主可以试下其他的编译器,比如:在VC6中,楼主举的例子不管是在栈上还是在堆上创建的A类的对象,他的成员i的值都是随机的!

#12


引用 11 楼 we_sky2008 的回复:
C/C++ code

class A
{
    int i;
};



A类没有定义构造函数,因为其成员是内置类型的,所以在构造A类对象时,
语言级别上,编译器应该只为其分配空间,不对其成员做任何的初始化,
这在在栈上和堆上创建对象来讲都是一样的,语言级别上来讲,值都应该是随机的
至于楼主所说的在堆上创建对象时,空间被memset过了,这最多算是编译器的扩展,标准中并……


class A
 { int i;}

main()
{
  A a;
  A *p= new A();

}

刚才在DEVC++中试了下,当写为如下形式时:
A *p= new A();//是被memset过的
A *p= new A;//是未被memset过的,值是随机的
搞不清楚了!

#13


引用 11 楼 we_sky2008 的回复:
C/C++ code

class A
{
    int i;
};



A类没有定义构造函数,因为其成员是内置类型的,所以在构造A类对象时,
语言级别上,编译器应该只为其分配空间,不对其成员做任何的初始化,
这在在栈上和堆上创建对象来讲都是一样的,语言级别上来讲,值都应该是随机的
至于楼主所说的在堆上创建对象时,空间被memset过了,这最多算是编译器的扩展,标准中并没有规定
……


学习之 大哥!

#14


(1) 堆中分配的内存按类型的默认构造方法进行初始化,对于内置类型一般为默认值0,对于类类型将调用默认构造函数进行初始化;
(2)对于全局变量同(1),对于局部变量,即栈中变量为随机值

#15


无论是在栈上,还是堆上开辟的内存,理论上都是随机的,具体可能和编译器有关。所以楼主所提出的说法是不正确的

#16


理论上都是随机的!!!!!楼主慎重,不要找规律!!!

#17


你把下面的A *p=new A();换成A *p=new A;的话你会发现在堆中分配的A也没有被初始化,和栈中分配的A一样。

当在类型后面加上一对括号且没有参数时表示用该类型的默认值初始化,对内置类型就是0。

建议你好好看看the c++ programming language。这是c++之父写的书,看完这本书,很多问题都明白了,另外一本就是C++ Standard - ANSI ISO IEC 14882 2003,这是c++标准。

#18


默认构造函数会把成员初始化,楼主研究的太深了!!

#19


又查了c++ 标准new A;和new A();可能是不同的!

5.3.4.15
A new-expression that creates an object of type T initializes that object as follows:
If  the new-initializer is omitted:
if T is a (possibly cv-qualified) non-POD class type (or array thereof), the object is default-
initialized (8.5).  If T is a const-qualified type, the underlying class type shall have a user-declared
default constructor.
— Otherwise, the object created has indeterminate value.  I T is a const-qualified type, or a (possibly
cv-qualified) POD class type (or array thereof) containing (directly or indirectly) a member of
const-qualified type, the program is ill-formed;
— If  the new-initializer is of the form (), the item is value-initialized (8.5);


8.5.5
To value-initialize an object of type T means:
if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is
called (and the initialization is ill-formed if T has no accessible default constructor);
if T is a non-union class type without a user-declared constructor, then every non-static data member
and base-class component of T is value-initialized;

#1


补充下 2) 看到有人是malloc一段内存 然后memset为0

#2


分配的地方不一样,new在堆上分配

#3


00415630  push        ebp  
00415631  mov         ebp,esp 
00415633  sub         esp,100h 
00415639  push        ebx  
0041563A  push        esi  
0041563B  push        edi  
0041563C  lea         edi,[ebp-100h] 
00415642  mov         ecx,40h 
00415647  mov         eax,0CCCCCCCCh 
0041564C  rep stos    dword ptr es:[edi] 
0041564E  mov         byte ptr [ebp-0DDh],0 
   A a; //这个时候a里面的i是随机值
  A *p= new A();//这个时候p里面的i是0
00415655  mov         dword ptr [ebp-0F8h],4 
0041565F  mov         eax,dword ptr [ebp-0F8h] 
00415665  push        eax  
00415666  call        operator new (41161Dh) 
0041566B  add         esp,4 
0041566E  mov         dword ptr [ebp-0ECh],eax 
00415674  cmp         dword ptr [ebp-0ECh],0 
0041567B  je          main+73h (4156A3h) 
0041567D  mov         ecx,dword ptr [ebp-0F8h] 
00415683  push        ecx  
00415684  push        0    
00415686  mov         edx,dword ptr [ebp-0ECh] 
0041568C  push        edx  
0041568D  call        @ILT+1860(_memset) (411749h) 
00415692  add         esp,0Ch 
00415695  mov         eax,dword ptr [ebp-0ECh] 
0041569B  mov         dword ptr [ebp-100h],eax 
004156A1  jmp         main+7Dh (4156ADh) 
004156A3  mov         dword ptr [ebp-100h],0 
004156AD  mov         ecx,dword ptr [ebp-100h] 
004156B3  mov         dword ptr [p],ecx 

#4


编译器就是这么定的,记住就行了。

#5


引用 3 楼 luciferisnotsatan 的回复:
Assembly code
00415630  push        ebp  
00415631  mov         ebp,esp 
00415633  sub         esp,100h 
00415639  push        ebx  
0041563A  push        esi  
0041563B  push        edi  
0041563C ……

学习了

#6


理论上,栈上对象也该调用默认构造函数,但这里没有。int这种内建类型默认设置为0。
同时,堆上也没有调用,只是用了个简单的memset。

#7


class A
 { 
 public:
 int i;};

int main(int argc, char *argv[])
{
00415630  push        ebp  
00415631  mov         ebp,esp 
00415633  sub         esp,10Ch 
00415639  push        ebx  
0041563A  push        esi  
0041563B  push        edi  
0041563C  lea         edi,[ebp-10Ch] 
00415642  mov         ecx,43h 
00415647  mov         eax,0CCCCCCCCh 
0041564C  rep stos    dword ptr es:[edi] 
   A a = A(); //这个时候a里面的i是随机值
0041564E  xor         eax,eax                         #eax 清0
00415650  mov         dword ptr [ebp-104h],eax 
00415656  mov         ecx,dword ptr [ebp-104h] 
0041565C  mov         dword ptr [a],ecx 
   int i = 1;
0041565F  mov         dword ptr [i],1 
  A *p= new A();//这个时候p里面的i是0
00415666  mov         dword ptr [ebp-0F8h],4 
00415670  mov         eax,dword ptr [ebp-0F8h] 
00415676  push        eax  
00415677  call        operator new (41161Dh) 
0041567C  add         esp,4 
0041567F  mov         dword ptr [ebp-0ECh],eax 
00415685  cmp         dword ptr [ebp-0ECh],0 
0041568C  je          main+84h (4156B4h) 
0041568E  mov         ecx,dword ptr [ebp-0F8h] 
00415694  push        ecx  
00415695  push        0    
00415697  mov         edx,dword ptr [ebp-0ECh] 
0041569D  push        edx  
0041569E  call        @ILT+1860(_memset) (411749h) 
004156A3  add         esp,0Ch 
004156A6  mov         eax,dword ptr [ebp-0ECh] 
004156AC  mov         dword ptr [ebp-10Ch],eax 
004156B2  jmp         main+8Eh (4156BEh) 
004156B4  mov         dword ptr [ebp-10Ch],0 
004156BE  mov         ecx,dword ptr [ebp-10Ch] 
004156C4  mov         dword ptr [p],ecx 
  printf("%d",a.i);
004156C7  mov         esi,esp 
004156C9  mov         eax,dword ptr [a] 
004156CC  push        eax  
004156CD  push        offset string "%d" (4237FCh) 
004156D2  call        dword ptr [__imp__printf (42850Ch)] 
004156D8  add         esp,8 
004156DB  cmp         esi,esp 
004156DD  call        @ILT+1290(__RTC_CheckEsp) (41150Fh)  


虽然还是没看到代码里有调默认构造函数(也没有临时对象生成),但输出就是0了。
所以你还是应该自己写构造函数。而不是听编译器由命

#8


引用 2 楼 bdmh 的回复:
分配的地方不一样,new在堆上分配

学习

#9


引用 8 楼 jiangchaomr 的回复:
引用 2 楼 bdmh 的回复:

分配的地方不一样,new在堆上分配

学习

多谢

#10


Hello * = new hello, 是堆内存分配。分配在你的数据和常量区。 Hello hello 是栈内存分配,分配在你的程序的尾巴部分。

#11



class A
{
    int i;
};


A类没有定义构造函数,因为其成员是内置类型的,所以在构造A类对象时,
语言级别上,编译器应该只为其分配空间,不对其成员做任何的初始化,
这在在栈上和堆上创建对象来讲都是一样的,语言级别上来讲,值都应该是随机的
至于楼主所说的在堆上创建对象时,空间被memset过了,这最多算是编译器的扩展,标准中并没有规定

标准中只是说了对于内置类型,支持一种特殊的构造语法,可将对象初始化为0,比如:
int *p = new int();

但是对于类类型来说,加不加最后的()都是一样的,都是调用缺省的构造函数,就像类A,其缺省的构造函数不会对其成员初始化,

楼主可以试下其他的编译器,比如:在VC6中,楼主举的例子不管是在栈上还是在堆上创建的A类的对象,他的成员i的值都是随机的!

#12


引用 11 楼 we_sky2008 的回复:
C/C++ code

class A
{
    int i;
};



A类没有定义构造函数,因为其成员是内置类型的,所以在构造A类对象时,
语言级别上,编译器应该只为其分配空间,不对其成员做任何的初始化,
这在在栈上和堆上创建对象来讲都是一样的,语言级别上来讲,值都应该是随机的
至于楼主所说的在堆上创建对象时,空间被memset过了,这最多算是编译器的扩展,标准中并……


class A
 { int i;}

main()
{
  A a;
  A *p= new A();

}

刚才在DEVC++中试了下,当写为如下形式时:
A *p= new A();//是被memset过的
A *p= new A;//是未被memset过的,值是随机的
搞不清楚了!

#13


引用 11 楼 we_sky2008 的回复:
C/C++ code

class A
{
    int i;
};



A类没有定义构造函数,因为其成员是内置类型的,所以在构造A类对象时,
语言级别上,编译器应该只为其分配空间,不对其成员做任何的初始化,
这在在栈上和堆上创建对象来讲都是一样的,语言级别上来讲,值都应该是随机的
至于楼主所说的在堆上创建对象时,空间被memset过了,这最多算是编译器的扩展,标准中并没有规定
……


学习之 大哥!

#14


(1) 堆中分配的内存按类型的默认构造方法进行初始化,对于内置类型一般为默认值0,对于类类型将调用默认构造函数进行初始化;
(2)对于全局变量同(1),对于局部变量,即栈中变量为随机值

#15


无论是在栈上,还是堆上开辟的内存,理论上都是随机的,具体可能和编译器有关。所以楼主所提出的说法是不正确的

#16


理论上都是随机的!!!!!楼主慎重,不要找规律!!!

#17


你把下面的A *p=new A();换成A *p=new A;的话你会发现在堆中分配的A也没有被初始化,和栈中分配的A一样。

当在类型后面加上一对括号且没有参数时表示用该类型的默认值初始化,对内置类型就是0。

建议你好好看看the c++ programming language。这是c++之父写的书,看完这本书,很多问题都明白了,另外一本就是C++ Standard - ANSI ISO IEC 14882 2003,这是c++标准。

#18


默认构造函数会把成员初始化,楼主研究的太深了!!

#19


又查了c++ 标准new A;和new A();可能是不同的!

5.3.4.15
A new-expression that creates an object of type T initializes that object as follows:
If  the new-initializer is omitted:
if T is a (possibly cv-qualified) non-POD class type (or array thereof), the object is default-
initialized (8.5).  If T is a const-qualified type, the underlying class type shall have a user-declared
default constructor.
— Otherwise, the object created has indeterminate value.  I T is a const-qualified type, or a (possibly
cv-qualified) POD class type (or array thereof) containing (directly or indirectly) a member of
const-qualified type, the program is ill-formed;
— If  the new-initializer is of the form (), the item is value-initialized (8.5);


8.5.5
To value-initialize an object of type T means:
if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is
called (and the initialization is ill-formed if T has no accessible default constructor);
if T is a non-union class type without a user-declared constructor, then every non-static data member
and base-class component of T is value-initialized;

#20