一、C 语言动态内存管理malloc/calloc/realloc/free四个核心函数都在cstdlib操作原始堆内存只分配 / 释放内存不会调用构造、析构函数。1、void* malloc(size_t size)分配 size 字节未初始化堆内存分配失败返回 NULL。int* arr (int*)malloc(sizeof(int) * 10);2、void* calloc(size_t num, size_t size)分配 num 个、每个 size 字节分配后内存全部置 0。3、void* realloc(void* ptr, size_t new_size)扩容 / 缩容已有内存ptr 为 NULL等价 mallocnew_size0等价 free原内存数据会拷贝到新空间旧内存自动释放。4、void free(void* ptr)释放堆内存只能释放 malloc/calloc/realloc 分配的内存free 空指针安全重复 free、free 栈变量 / 全局变量 → 未定义行为崩溃。二、C 原生动态内存 new /delete1. 基础用法// 单个对象 int* p new int(10); delete p; // 对象数组 int* arr new int[5]{1,2,3,4,5}; delete[] arr; // 数组必须带[]否则只调用第一个元素析构内存错乱2. new 底层两步operator new底层调用 malloc 开辟堆内存调用构造函数初始化对象。3. delete 底层两步调用对象析构函数释放对象内部资源operator delete调用 free 归还堆内存。4. new/delete 相比 malloc/free 的优势自动调用构造、析构适配 C 类、自定义对象自带类型安全无需强制类型转换支持数组语法区分单个对象与数组释放。5. new/delete 存在大量问题忘记 delete → 内存泄漏同一块内存多次 delete / 栈指针 delete → 程序崩溃函数中途抛异常、提前 returndelete 执行不到多函数传递裸指针内存所有权模糊没人负责释放异常安全差new 成功后如果后续代码抛异常delete 不会执行。根本解决方案RAII 智能指针三、RAII 核心思想Resource Acquisition Is Initialization 资源获取即初始化1. 核心定义把资源获取写在类的构造函数资源释放写在类的析构函数利用栈对象自动生命周期栈上局部对象离开作用域正常 return、break、抛出异常时编译器一定会自动调用析构函数保证资源释放。四、C 标准智能指针memory全部基于 RAII 实现智能指针本质是封装裸指针的栈对象依靠 RAII 自动释放堆内存彻底替代手动 delete。分三类unique_ptr、shared_ptr、weak_ptr1. std::unique_ptr 独占智能指针最常用特性独占所有权一块内存只能被一个 unique_ptr 持有禁止拷贝构造 / 拷贝赋值只支持移动语义std::move无引用计数运行时开销几乎和裸指针一致性能最优代码示例// 推荐一步分配内存异常安全 auto up std::make_uniqueint(666); // auto up2 up; // 编译报错禁止拷贝 auto up2 std::move(up); // 所有权转移up变为空 // 离开作用域自动释放内存适用场景资源只需要单一管理者绝大多数堆内存场景优先 unique_ptr。.最常用成员函数get()获取裸指针reset()释放 / 更换资源release()交出裸指针自身置空2. std::shared_ptr 共享智能指针特性共享所有权内部维护原子引用计数器支持拷贝拷贝时引用计数 1智能指针销毁 / 覆盖赋值时计数 - 1引用计数变为 0 时自动释放堆内存性能损耗原子操作多线程同步开销高于 unique_ptr致命缺陷循环引用会导致内存泄漏。代码示例auto sp1 std::make_sharedstd::string(test); auto sp2 sp1; // 计数1两个指针共用一块内存.最常用成员函数get()获取裸指针reset()释放 / 更换资源use_count()获取当前引用计数循环引用泄漏场景面试高频两个类互相持有对方 shared_ptr引用计数永远不为 0内存无法释放struct A { std::shared_ptrB b; }; struct B { std::shared_ptrA a; }; void leakDemo() { auto a std::make_sharedA(); auto b std::make_sharedB(); a-b b; b-a a; // 函数结束a、b销毁但互相持有计数内存泄漏 }3. std::weak_ptr 弱智能指针配套 shared_ptr 解决循环引用特性不增加引用计数不拥有内存所有权仅做 “观察者”只能由 shared_ptr 构造使用前调用.lock()升级为 shared_ptr判断内存是否存活.expired()。改造上面循环引用解决泄漏struct A { std::shared_ptrB b; }; struct B { std::weak_ptrA a; // 改用weak_ptr不增加计数 };常用成员函数lock()升级成 shared_ptr用来访问对象expired()判断对象是否已经销毁reset()清空弱指针use_count()查看强引用数量4. make_unique /make_shared 为什么比 new 好内存分配一步到位make_shared 把控制块 对象内存分配在同一块连续堆减少内存碎片缓存友好异常安全若func(std::shared_ptrT(new T), func_throw())编译器可能先执行 new T 分配内存再执行抛异常函数内存分配成功但无智能指针接管直接泄漏make 系列将分配和构造绑定不会出现裸内存悬空。