数据的类型:
对于程序而言,数据的类型大概有以下几种:局部数据、静态数据和全局数据、常量数据、动态申请数据。这些数据别有特点,服务于实际需求。
而程序在运行时,这些数据由于不同的特性和用途,分别存储在内存的不同位置中。
虚拟进程地址空间:
把内存大致进行划分,可以得到一份数据存储分布图。
new && delete
在C语言中有配套的malloc/realloc/calloc 和 free 的动态申请/销毁空间函数。
在C++中同样也可以用C语言的方法,但其另有一套 new 和 delete 关键字的玩法,且比上述方法更加简便。
//C
int* i = (int*)malloc(sizof(int));
free(i);
//CPP
int* j = new int;
delete j;
//对于数组而言
//C
int* arr1 = (int*)(sizof(int) * 10);
free(arr1);
//CPP
int* arr2 = new int[10];
delete[] arr2;
这两种方法各成一派,混合使用很可能会出现错误。
初始化:
注意,new && delete 这一套方法是不会对开辟的动态内存空间进行初始化。
//对单个数据进行初始化
int* k = new int(0);
//对数组进行初始化
int* arr3 = new int[10]{1,2,3};//其余被初始化为0
//如果是对类的多个对象进行初始化,那么除了默认构造函数是全缺省参数外,其它情况下都是要将初始化写全
A* arr4 = new A[3]{A(2,2), A(1,1), A(4,3)};
//这里也体现了匿名函数的特点
这种初始化的方法比起C语言中的方法而言十分方便。
使用细节:
这两套方案在针对内置类型进行使用时,除了在用法上的差别,其它并无太大不同。
但对于自定义类型,new会调用构造函数,delete会调用析构函数。
两套方法的区别:
从底层的角度上看,由于C++自定义类型的广泛使用,传统的malloc/free方法对于开辟空间并且初始化显得比较麻烦,malloc/free方法只是申请了空间,并未进行初始化。
new/delete方法是先用operate new方法开辟空间,再调用构造函数对资源进行初始化。在销毁时,是先用析构函数对资源进行销毁,再使用operate delete方法对空间进行释放。
浅显一点地看,使用malloc申请空间时,需要对空间大小进行计算(使用sizeof操作符可以很大程度上减少计算量),需要进行强转类型(一般由对应类型指针来“接收”),如果失败了会返回NULL,判断时要注意。而使用new申请空间时,上面的过程已经集成好了,相当于流水线,只是在申请失败时会抛出异常,处理时要有捕捉异常的代码。
cout小知识:
cout 具有自动识别功能,本质是函数重载,其可以打印不同类型的数据,但以下涉及指针的比较特殊。
char* p1 = new char[1024*1024];
cout << p1 << endl;//cout会将char*识别成字符串,直到遇到\0才停止,因此这很可能会出现乱码
char* p1 = new char[1024*1024];
cout << (void*)p1 << endl;//对p1进行强转就会只打印开辟空间的地址
内存泄漏:
内存泄漏不是物理意义上的内存丢失,而是由于设计失误,应用程序未能将不再使用的内存完整地释放返回给操作系统。
普通程序的内存泄漏问题不大,哪怕崩溃了只要程序一结束内存就回来了。
但是对应像后台服务那样长期运行的程序而言,内存泄漏造成的影响是持久且明显的。