一,C/C++内存分布
内存区域的大概介绍:
C/C++中,我们目前需要了解的内存区域是栈区、堆区、静态区、常量区。其中,栈区用于临时存储数据,如函数的栈帧,局部变量等。堆区一般用来存储动态开辟的空间,如malloc、calloc、realloc、new等开辟的空间。静态区原名是代码段,一般存储全局变量和静态数据,在整个程序都可以使用。常量区用来存储常量,如字面量等。这些东西之前有过说明,这里我们简单提一下即可。
以上东西全为基础,接下来我们来看看以下代码中的数据的存储空间。
int globalVar = 1; static int staticGlobalVar = 1; void Test() { static int staticVar = 1; int localVar = 1; int num1[10] = { 1, 2, 3, 4 }; char char2[] = "abcd"; const char* pChar3 = "abcd"; int* ptr1 = (int*)malloc(sizeof(int) * 4); int* ptr2 = (int*)calloc(4, sizeof(int)); int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4); free(ptr1); free(ptr3); } 选项 : A.栈 B.堆 C.数据段(静态区) D.代码段(常量区) globalVar在 C staticGlobalVar在 C staticVar在 C localVar在 A num1 在 A char2在 A * char2在 A pChar3在 A * pChar3在 D ptr1在 A * ptr1在 B
分析:前5个好理解,要注意的是后面六个选项。char2在函数栈帧中创建了一个数组,其代表了首元素的地址,存储在栈区中,而*char2代表首元素,也存储在栈区中。pChar3要注意的是,这里的const修饰的是*pChar3,即 "abcd" 是一个字面量,存储在常量区中,而pChar3是一个指针,存储在栈区中。ptr1的类型是int* ,指向堆区中开辟动态空间的首地址,因此,ptr1存储在栈区中,*ptr1指向数据,存储在堆区中。
二,C++动态开辟空间
1,new/delete操作内置类型
我们都知道,C语言中有malloc、calloc、realloc、free语法进行动态空间的管理,而C++中通过new和delete操作符进行动态空间管理。其中new用来开辟空间,delete用来释放空间。其中,new可以对创建的空间进行初始化。
//动态开辟一个int型的空间 int* p1 = new int;//里面是随机值,不会初始化 int* p2 = new int(1);//动态开辟一个空间并初始化为1 //动态开辟多个int型的空间 int* p3 = new int[5]{ 1, 2 };//动态开辟5个空间并初始化为1 2 0 0 0 int* p4 = new int[10];//里面是随机值,不会初始化 //删除开辟一个空间 delete p1; delete p2; //删除开辟多个空间 delete[] p3; delete[] p4;
注意:C++中delete在释放中不支持一次多次释放,如下:
//下面是错误的用法 delete p1,p2; delete[] p3,p4;
new操作符在没有指定初始化的时候系统不会自动初始化。
#include <iostream> #include <string> using namespace std; int main() { int n = 2; int* a = new int[n]; a[0] = 0; a[1] = 1; a = new int[2 * n];//重新分配空间大小,里面全部是随机值 return 0; }
2,new和delete操作自定义类型
这里要说明的是,操作自定义时,new/delete 和 malloc/free的最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数进行空间的初始化和释放。
class A { public: A(int a = 0) : _a(a) { cout << "A():" << this << endl; } ~A() { cout << "~A():" << this << endl; } private: int _a; }; int main() { //通过调试可见,动态开辟空间初始化过程中调用了构造函数 //只调用一次构造函数 A* p1 = new A; A* p2 = new A(1); A aa1(1); A aa2(1); A aa3(1); //调用了三次构造函数 A* p3 = new A[3]{ aa1, aa2, aa3 }; A* p4 = new A[3]{A(2), A(2), A(2) }; A* p5 = new A[3]{ 3, 3, 3 }; //通过调试可见,动态空间释放过程中调用了析构函数 //只调用一次析构函数 delete p1; delete p2; //调用了三次析构函数 delete[] p3; delete[] p4; delete[] p5; return 0; }
总的来说:
new的本质:开空间+调用构造函数初始化。
delete的本质:调用析构函数释放空间。
通过以上可总结出,在开辟和释放的过程中,new关键字开辟了多少个动态类型空间,将会调用多少次构造函数;delete关键字释放了多少个动态类型空间,将会调用多少次析构函数。其中new开辟的空间无论是否进行初始化,构造函数都会被调用。
C/C++内存管理--2https://developer.aliyun.com/article/1424646?spm=a2c6h.13148508.setting.20.214f4f0eqBSn46