1.内存分布
C/C++将内存大体上分为四个区域:栈区、堆区、静态区(数据段)、常量区(代码段)。
栈区:用来存储函数调用时的临时信息的结构,存放为运行时函数分配的局部变量、函数参数、返回数据、返回地址等。
堆区:程序员自己使用malloc或new自己申请出来存的地方。(动态内存分配)
静态区: static修饰的数据,全局数据,存放的位置。
常量区:不会改变的常量,存在这里。
看下面一段代码,回答问题:
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); }
看上面一段代码,请回答如下:
2. new/delete关键字
2.1 操作内置类型
int main() { //动态申请一个int 类型的空间 int* ptr1 = new int; delete ptr1; //释放ptr1 // 动态申请一个int 类型的空间,并初始化为 5 int* ptr2 = new int(5); delete ptr2; //释放ptr2 // 动态申请5个int 类型的空间 int* ptr3 = new int[5]; delete[] ptr3; // 释放ptr3,注意怎么new的怎么delete 动态申请5个int 类型的空间,并初始化 int* ptr4 = new int[5]{ 1,2,3 }; delete[] ptr4; // 释放ptr4,注意怎么new的怎么delete return 0; }
**注意:new 对应 delete,new [] 对应 delete [] 。**不可用错。
操作自定义类型
new 和 delete 除了申请和释放空间外,会自动调用构造函数和析构函数。
class A { public: A(int a = 0) { cout << "A()" << endl; } ~A() { cout << "~A()" << endl; } private: int _day; int _year; int _month; }; int main() { A* p1 = new A(1); //一次构造 delete p1; //一次析构 A* p2 = new A[5]; // 五次构造 delete[] p2; //五次析构 return 0; }
3. opeartor new 与 operator delete函数
new和delete是 用户进行动态内存申请和释放的操作符,operator new 和 operator delete 是系统提供的全局函数,new在底层调用 operator new 全局函数来申请空间,delete在底层通过 operator delete 全局函数来释放空间。
其中:
operator new:该函数实际通过malloc来申请空间,申请成功直接返回;失败时,尝试执行空间不足应对策略,如果用户对该措施设置了,继续申请空间,否则抛异常。
operator delete:该函数最终是通过free()来释放空间的。
通过该定义也可以看出,free()其实也是一个重命名,真正的函数名是后面的。
4. new 和 delete 原理
4.1 内置类型
如果申请的是内置类型空间,new和malloc,delete和free基本类似,不同的地方是:new和delete申请和释放的是单个元素空间,new[]和delete[]申请和释放的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。
4.2 自定义类型
new的原理
1.调用operator new 申请空间
2.在申请的空间上执行构造函数,完成对象的构造。
delete 原理
1.在空间上执行析构函数,完成对象中资源的清理工作
2.调用operator delete函数释放对象的空间
newT[N] 原理
1.调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请。
2.在申请的空间上执行N次构造函数
delete[] 原理
1.在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理。
2.调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间
如下例子总结:
5.定位new表达式(placement-new)
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
使用语法:
new (place_address) type 或者new (place_address) type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表。
new(p1)A; //如果A的构造函数有参数,此处需要传参 nwe(p2)A(10); // 初始化参数为10
6. malloc/free 和 new/delete的区别
共同点:
都是从堆上申请空间,并需要手动释放。
不同点:
malloc和free是函数,new和delete是关键字。
malloc申请的空间不会初始化,new可以调用构造函数完成初始化。
malloc申请空间时,需要手动计算空间大小并传递,new只需在其后面跟上空间的类型即可,如果是多个对象,[]中指定个数即可。
malloc返回值是void*,在使用时必须强转,new不需要,因为new后面跟的是空间类型。
malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是需要捕获异常。
申请自定义类型时,malloc/free 只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成对象空间中资源的清理。
7. 内存泄漏
相关知识后续会继续补充。。。