一、上期回顾
掌握函数模板、类模板、泛型编程、模板特化,理解了 STL 容器能适配任意类型的底层原因。今天攻坚C++ 内存管理,搞定 new/delete、内存分区、野指针、内存泄漏四大核心痛点。
二、C/C++ 程序内存五大分区
程序运行时内存划分为 5 块,面试必背:
- 栈区:局部变量、函数形参、栈对象;自动分配自动释放
- 堆区:new/malloc 开辟的空间;手动申请手动释放
- 全局 / 静态区:全局变量、static 静态变量;程序全程存在
- 常量区:字符串常量、const 全局常量;只读不可修改
- 代码区:存放二进制程序指令,只读
三、malloc/free 与 new/delete 核心区别
1. C 语言 malloc/free
- 只分配原始内存,不调用构造、析构函数
- 需要强转类型、手动计算字节大小
- 不会初始化内存
int* p = (int*)malloc(sizeof(int)); free(p);2. C++ new/delete
- 分配内存 + 自动调用构造函数
- 释放内存 + 自动调用析构函数
- 无需计算大小、无需强转
- 支持数组形式 new [] /delete []
int* p = new int; delete p; // 数组开辟 int* arr = new int[5]; delete[] arr;核心区别总结
- new 自动调用构造,malloc 只开空间
- new 无需强转、自动计算大小
- delete 自动调用析构,free 直接回收内存
- 数组必须配对
new[]和delete[]
四、new 的三种使用形式
// 1. 普通开辟单个变量 int* p1 = new int; // 2. 开辟并初始化 int* p2 = new int(100); // 3. 开辟数组 int* p3 = new int[5];五、内存泄漏成因与规避
什么是内存泄漏
堆空间用new申请后,没有 delete 释放,程序不退出内存一直占用。
常见泄漏场景
- 函数内 new,没有返回也没有释放
- 指针重新赋值,旧地址丢失无法释放
- 类中堆成员,析构函数没写 delete
避坑原则
谁申请,谁释放;成对使用 new/delete
六、野指针成因与危害
野指针定义
指向非法未知内存的指针,没有有效指向。
产生原因
- 指针未初始化,随机地址
- 指针指向栈变量,变量销毁后指针悬空
- 内存释放后,未把指针置空
规避方法
- 定义指针初始化为
nullptr - 释放内存后立刻置空
- 不访问悬空指针
// 规范写法 int* p = new int; delete p; p = nullptr; // 置空,避免野指针七、内存经典错误示范
错误 1:重复释放
int* p = new int; delete p; delete p; // 崩溃,重复释放错误 2:数组不匹配 delete []
int* arr = new int[5]; delete arr; // 错误,必须 delete[]错误 3:野指针访问
int* p; *p = 10; // 未初始化,野指针崩溃八、构造析构与 new/delete 联动演示
#include <iostream> using namespace std; class Test { public: Test(){cout << "构造函数调用" << endl;} ~Test(){cout << "析构函数调用" << endl;} }; int main() { // 栈对象:自动构造、自动析构 Test t1; // 堆对象:new触发构造,delete触发析构 Test* t2 = new Test; delete t2; return 0; }运行结果:
构造函数调用 构造函数调用 析构函数调用 析构函数调用九、今日核心总结
- 内存五分区:栈、堆、全局静态、常量、代码区
- new/delete 比 malloc/free 多了构造析构调用
- 数组必须严格配对
new[]和delete[] - 内存泄漏:new 不 delete;野指针:未初始化 / 悬空指针
- 开发规范:指针初始化为空、释放后置空、成对申请释放
十、课后练习
- 用 new 开辟单个 int 并初始化,delete 释放
- 尝试不 delete 观察内存泄漏逻辑
- 定义未初始化指针,理解野指针危害