1. 什么是智能指针智能指针是 C 标准库提供的一种封装了原始指针的类模板核心作用是自动管理动态内存避免手动 new/delete 导致的内存泄漏如异常抛出时忘记释放内存或重复释放等问题。它的本质是利用RAII资源获取即初始化机制将动态内存的生命周期与智能指针对象的生命周期绑定 —— 当智能指针对象离开作用域时其析构函数会自动调用 delete 释放所管理的内存2. 常用智能指针的类型有哪些三大常用智能指针的类型std::unique_ptr基本特性独占所有权同一时间只能有一个 unique_ptr 管理某块内存不允许拷贝只能移动适用场景管理单个对象或数组明确内存归属唯一的场景代码语言javascriptAI代码解释#include memory using namespace std; int main() { //1.管理单个int对象 unique_ptrint ptr1(new int(10)); //2.或用更安全的make_uniqueC14 auto ptr2 make_uniqueint(20); //3.不允许拷贝编译报错 // unique_ptrint ptr3 ptr1; //4.允许移动所有权转移 unique_ptrint ptr4 move(ptr1); } // 离开作用域时ptr2、ptr4自动释放内存std::shared_ptr基本特性共享所有权通过引用计数记录有多少个 shared_ptr 管理同一块内存当计数为 0 时自动释放适用场景需要多个指针共享同一资源如容器中存储的对象被多个地方引用代码语言javascriptAI代码解释#include memory using namespace std; int main() { auto ptr1 make_sharedint(30); shared_ptrint ptr2 ptr1; // 引用计数变为2 { //使用大括号定义了一个 “临时代码块” --- 定义了一个局部作用域 shared_ptrint ptr3 ptr1; // 引用计数变为3 } // ptr3销毁引用计数变回2 } // ptr1、ptr2销毁引用计数变为0内存释放std::weak_ptr基本特性弱引用不增加引用计数用于解决 shared_ptr 的循环引用问题两个 shared_ptr 互相引用导致计数无法归零适用场景作为观察者关联共享资源不参与所有权管理代码语言javascriptAI代码解释#include memory using namespace std; struct Node { weak_ptrNode next; // 用weak_ptr避免循环引用 }; int main() { auto node1 make_sharedNode(); auto node2 make_sharedNode(); node1-next node2; // weak_ptr不增加计数 node2-next node1; } // 计数正常归零内存释放总结独占资源→unique_ptr— 适合 “一对一” 的场景共享资源→shared_ptr— 适合 “多对一” 的场景观察资源→weak_ptr— 解决循环引用3. 怎么使用智能指针使用 C 智能指针的核心是利用其自动管理内存的特性避免手动new/delete导致的问题。以下是三种常用智能指针的具体使用方法和场景一、std::unique_ptr独占所有权代码语言javascriptAI代码解释#include iostream #include memory // 需包含智能指针头文件 using namespace std; int main() { /*--------------- 创建 unique_ptr管理单个对象---------------*/ //方式1直接绑定 new 分配的内存不推荐存在异常安全风险 unique_ptrint ptr1(new int(10)); //方式2用 make_unique 创建C14 推荐更安全 auto ptr2 make_uniqueint(20); // 自动推导类型 /*--------------- 访问所管理的对象同普通指针---------------*/ *ptr2 30; // 修改值 cout *ptr2 endl; // 输出30 /*--------------- 转移所有权只能用 move原指针会变为空---------------*/ unique_ptrint ptr3 move(ptr2); //注意ptr2 不再拥有内存 if (ptr2 nullptr) { cout ptr2 已为空 endl; } /*--------------- 管理动态数组需指定数组类型---------------*/ unique_ptrint[] arr_ptr make_uniqueint[](5); // 5个int的数组 arr_ptr[0] 1; // 数组访问 } // 离开作用域时所有 unique_ptr 自动释放内存无需手动 delete在这里插入图片描述二、std::shared_ptr共享所有权代码语言javascriptAI代码解释#include iostream #include memory using namespace std; int main() { //1.创建 shared_ptr推荐用 make_shared auto ptr1 make_sharedint(100); // 引用计数 1 //2.共享所有权拷贝指针时引用计数增加 shared_ptrint ptr2 ptr1; // 引用计数 2 shared_ptrint ptr3 ptr2; // 引用计数 3 //3.访问对象同普通指针 *ptr3 200; cout *ptr1 endl; // 输出200所有指针指向同一内存 //4.查看引用计数use_count() 仅用于调试 cout 计数 ptr1.use_count() endl; // 输出3 //5.局部作用域演示计数变化 { shared_ptrint ptr4 ptr1; // 计数 4 } // ptr4 销毁计数 3 //6.手动释放重置指针计数减少 ptr2.reset(); // ptr2 不再指向内存计数 2 } // ptr1、ptr3 销毁计数 0 → 内存自动释放在这里插入图片描述三、std::weak_ptr弱引用解决循环引用代码语言javascriptAI代码解释#include iostream #include memory // 包含智能指针所需的头文件 using namespace std; // 定义链表节点结构 // 场景链表节点之间可能互相引用容易引发shared_ptr的循环引用问题 struct Node { int value; // 节点存储的值 weak_ptrNode next; // 指向链表下一个节点的弱指针 //关键使用weak_ptr而非shared_ptr避免循环引用 }; int main() { //1.创建两个共享指针分别管理两个Node对象 auto node1 make_sharedNode(); // node1的引用计数为1 auto node2 make_sharedNode(); // node2的引用计数为1 //注意 make_shared是创建shared_ptr的推荐方式安全且高效 //2.构建节点间的互相引用关系 node1-next node2; // weak_ptr接收shared_ptr时不增加node2的引用计数仍为1 node2-next node1; // 同理node1的引用计数仍为1 //注意若此处用shared_ptr会导致引用计数循环增加无法归零 //3.1temp是有效的shared_ptr说明node2仍存在 if (auto temp node1-next.lock()) //注意访问weak_ptr指向的对象必须通过lock()方法转换为shared_ptr { cout node2 有效 endl; } //3.2若node2已被释放进入此分支 else { cout node2 已释放 endl; } /* 说明lock()的作用检查被引用的对象是否还存在 * 1. 若存在返回一个指向该对象的shared_ptr此时引用计数临时1 * 2. 若已释放返回空的shared_ptr */ } // main函数结束局部变量node1和node2开始销毁 // 1. node2的引用计数从1减为0 → 其管理的Node对象被释放 // 2. node1的引用计数从1减为0 → 其管理的Node对象被释放 // 3. 由于使用weak_ptr没有循环引用所有内存正常释放无内存泄漏在这里插入图片描述4. 为什么需要智能指针在 C 中智能指针的出现主要是为了解决手动管理动态内存时容易出现的问题其核心价值在于自动管理内存生命周期避免内存相关的 bug。具体来说需要智能指针的原因可以从以下几个方面理解1. 避免内存泄漏手动管理动态内存使用new分配、delete释放时若因逻辑疏漏导致delete未执行会造成内存泄漏已分配的内存无法回收直到程序结束代码语言javascriptAI代码解释void func() { int* ptr new int(10); // 分配内存 if (someCondition) { return; // 提前返回导致后续的delete未执行 } delete ptr; // 若if条件成立此行不会执行内存泄漏 }智能指针会在自身生命周期结束时如超出作用域、被销毁自动调用delete无论程序执行路径如何即使有提前返回、异常抛出等都能保证内存被释放2. 防止重复释放手动释放内存时若对同一块内存多次调用delete会导致未定义行为程序崩溃、数据损坏等代码语言javascriptAI代码解释void func() { int* ptr1 new int(10); int* ptr2 ptr; // 两个指针指向同一块内存 delete ptr1; delete ptr2; // 重复释放行为未定义 }智能指针通过引用计数等机制追踪内存的引用情况只有当最后一个引用它的智能指针被销毁时才会真正释放内存避免重复释放3. 应对异常安全当程序抛出异常时手动管理的内存可能因delete语句被跳过而泄漏代码语言javascriptAI代码解释void func() { int* ptr new int(10); try { someOperation(); // 若此函数抛出异常 } catch (...) { // 如果发生了异常且未在catch中手动释放ptr内存泄漏 throw; } delete ptr; // 如果未发生了异常ptr指向的资源将在这里释放 }智能指针的析构函数会在异常发生时被自动调用C 的栈展开机制确保内存释放无需手动在异常处理中额外处理