TypeCodes

C++中使用vs2015和g++对new开辟的堆内存是否初始化的分析

在C++中使用new运算符在堆中申请一内存块的使用权的同时还可以执行对该内存块的初始化工作。下面通过使用2个类对象和2个基本数据类型来分析使用new class_objectnew class_object()new intnew int()对这块内存的初始化情况。

1 示例程序

这里用下面这个C++程序作为演示,在后面两个小节中分别使用g++和vs2015来编译。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/** 
 * @FileName    gccvsheapnewinit1.cpp
 * @Describe    A simple example for using new to allocating mem and initialize it compiled with visual studio and g++.
 * @Author      vfhky 2017-03-14 23:24 https://typecodes.com/cseries/gccvsheapnewinit1.html
 * @Compile     g++ gccvsheapnewinit1.cpp -o gccvsheapnewinit1
 */
#include <iostream>
#include <stdio.h>
using namespace std;

//类A中是否开启默认构造函数
#define DEFAULTFUN 0

class A
{
public:
    int i_value;
#if DEFAULTFUN
    //无参构造函数
    A():i_value(10){}
#endif
};

int main( int argc, char **argv )
{
    A *obj1 = new A;
    //如果类A中没有自定义的构造函数(调用编译器合成的默认构造函数,不会对数据成员初始化),如果不加括号,则打印1个随机数;如果有自定义的构造函数,那么会调用这个构造函数进行初始化(本例为10)。
    cout << "new A=[" << obj1->i_value << "]" << endl;
    delete obj1;

    A *obj2 = new A();
    //如果类A中没有自定义的构造函数(调用编译器合成的默认构造函数),但是接着会对内存(各个成员变量)进行初始化(默认为0);如果自定义了构造函数,那么会调用这个构造函数进行初始化(本例为10)。
    cout << "new A()=[" << obj2->i_value << "]" << endl;
    delete obj2;

    cout << "----------------" << endl;

    //int类型中没有默认构造函数,如果不加括号,那么不会初始化。
    int *i_arra = new int[20];
    printf( "new int[10]=[%d]\n", *(i_arra+10) );
    delete i_arra;

    //int类型中没有默认构造函数,如果加括号,那么会初始化为0。
    int *i_arrb = new int[20]();
    printf( "new int[10]()=[%d]\n", *(i_arrb+10) );
    delete i_arrb;

    return 0;
}

2 使用g++编译器进行编译并执行

无论是否将DEFAULTFUN的值设置为1(即打开类A中的默认构造函数),在使用g++编译器编译并执行的输出结果都如下图所示。从图中可以看出在使用new运算符开辟了内存后,会自动对这块内存进行初始化。因此,图中类A的两个对象obj1和obj2对应的数据成员i_value的值都为0,而且整型指针变量指向偏移量为10的那个整数也都是0。

使用g++编译后执行输出的结果

3 在visual studio 2015中进行编译并执行

分别把上面程序中的DEFAULTFUN的值设置为0和1,也就是测试类中是否包含自定义的构造函数对使用new运算符开辟内存并初始化的影响,然后在vs2015中进行编译和执行,具体操作和对应结果如下。

3.1 把DEFAULTFUN的值设置为0

DEFAULTFUN的值设置为0,然后在visual studio 2015中进行编译并执行,得到的结果如下图所示。对比类A的对象obj1和obj2的数据成员的输出值可以得出结论:如果类A中没有自定义的构造函数,那么new Anew A()会调用编译器合成的默认构造函数,但是只有new A()会对这块内存(各个成员变量)进行初始化(默认为0)。

在visual studio2015中编译执行输出的结果

3.2 把DEFAULTFUN的值设置为1

DEFAULTFUN的值设置为1,然后在visual studio 2015中进行编译并执行,得到的结果如下图所示。对比类A的对象obj1和obj2的数据成员的输出值可以得出结论:如果自定义了构造函数,那么不论是new A还是new A()都会调用这个构造函数进行初始化(本例为10)。

在visual studio2015中编译执行输出的结果

4 总结

从第2小节的结果可以看出,对于g++编译器来说,无论是使用new class_objectnew class_object()new intnew int()都会对申请的这块内存进行初始化。

从第3和第4小节的结果可以看出,对于visual studio 2015编译器来说他们对上述new运算符的操作有不同的结果,具体总结如下:

对于基本数据类型(例如int, char等待)在使用new开辟申请内存空间时,如果使用new data_type[numbers]不会做内存的初始化操作;而使用new data_type[numbers]()时除了申请内存空间外还会把这块内存中所有的数据初始化为0。

对于对象类型(例如string以及自定义的类对象等)在使用new开辟申请内存空间时,如果没有自定义构造函数,那么使用new data_type[numbers]和使用new data_type[numbers]()都会调用由编译器合成的默认构造函数,但是new data_type[numbers]()还会把这块内存中所有的数据初始化为0;如果自定义了构造函数,那么使用new data_type[numbers]和使用new data_type[numbers]()都会调用由编译器合成的默认构造函数,然后进行初始化(例中为10)。

打赏支持

Comments »