C++智能指针详解 - 实践

news/2026/1/22 20:02:26/文章来源:https://www.cnblogs.com/gccbuaa/p/19518883

请添加图片描述


文章目录

  • 引言
  • 1.智能指针的核心设计思想:RAII
    • 1.1.“RAII”原理
    • 1.2.智能指针的实现
  • 2.C++标准库中的智能指针
    • 2.1.`auto_ptr`
    • 2.2.`unique_ptr`:独占型智能指针
    • 2.3.`shared_ptr`:共享型智能指针
    • 2.4.`weak_ptr`:弱引智能指针
  • 3.智能指针的关键问题与解决方法
    • 3.1.`shared_ptr`的循环引用问题
    • 3.2.非new资源的释放(删除器)
    • 3.3.线程安全问题
  • 4.内存泄露的解决方案
    • 4.1.内存泄漏的定义与危害
    • 4.2.如何解决内存泄露问题
  • 5.C++智能指针的演进关系
  • 结语


引言

在C++动态内存管理过程中,如果用new分配内存,常常会因异常、代码的逻辑缺陷等,未能正常执行delete,导致内存泄漏,这种bug通常十分隐蔽,不好直接找出错误部分。而智能指针基于RAII设计思想,将资源管理与对象生命周期绑定实现内存的自动释放,大大降低了内存泄漏风险。


1.智能指针的核心设计思想:RAII

1.1.“RAII”原理

  • RAII(Resource Acquisition Is Initialization),即“资源获取即初始化”,他是一种管理资源的类的设计思想。其核心本质是:将资源(内存、文件指针等)的获取与对象的初始化绑定,资源的释放与对象的析构绑定。当对象被创建时,通过构造获取资源;对象生命周期结束时,自动调用析构,释放资源。无论程序正常执行还是异常退出,对象都会被销毁,避免了资源泄露的风险

1.2.智能指针的实现

代码示例:智能指针的简化实现

template<class T>class SmartPtr {public:// 构造时获取资源(RAII)SmartPtr(T* ptr) : _ptr(ptr) {}// 析构时释放资源(RAII)~SmartPtr() {cout << "delete[] " << _ptr << endl;delete[] _ptr;}// 重载运算符,模拟指针行为T& operator*() { return *_ptr; }T* operator->() { return _ptr; }T& operator[](size_t i) { return _ptr[i]; }private:T* _ptr; // 管理的原始指针};

通过使用智能指针,无需手动delete,对象销毁时资源会自动释放,即使发生异常也不会泄露。


2.C++标准库中的智能指针

C++便准库(<memory>头文件)中,提供了4种智能指针,分别适用于不同场景。

2.1.auto_ptr

auto_ptr<Date> ap1(new Date);auto_ptr<Date> ap2(ap1); // ap1管理权转移给ap2,ap1悬空// ap1->_year++; // 空指针访问,崩溃风险

2.2.unique_ptr:独占型智能指针

  • 特性:C++11推出,核心是 “独占资源”,禁止拷贝(仅支持移动语义move),确保同一时刻只有一个智能指针管理资源。
  • 适用场景:无需拷贝的单所有权场景。
  • 代码示例:
unique_ptr<Date> up1(new Date);// unique_ptr<Date> up2(up1); // 编译报错,禁止拷贝unique_ptr<Date> up3(move(up1)); // 支持移动,up1悬空(需谨慎使用)

2.3.shared_ptr:共享型智能指针

  • 特性:C++11推出,支持拷贝和移动,通过引用计数实现资源共享。
  • 核心原理:
    (1)维护一个堆上的引用计数变量_pcount,记录当前管理该资源的shared_ptr数量;
    (2)构造时:引用计数初始化为1;
    (3)拷贝时;引用计数+1;
    (4)析构时:引用计数-1。
  • 应用场景:需要多线程共享资源、多个对象共同管理同一资源的场景。
  • 代码示例:
shared_ptr<Date> sp1(new Date);shared_ptr<Date> sp2(sp1); // 拷贝,引用计数=2shared_ptr<Date> sp3 = make_shared<Date>(2024, 9, 11); // 推荐:直接初始化资源cout << sp1.use_count() << endl; // 输出2,查看引用计数
  • 注意:推荐使用make_shared<T>(args)构造,相比直接new,能减少内存分配次数,代码执行效率更高,且能减少内存泄露风险。

2.4.weak_ptr:弱引智能指针

  • 特性:与RAII无关,不管理资源,仅作为shared_ptr的辅助工具,用来绑定shared_ptr时不增加引用计数,不参与资源释放。
  • 核心用途:解决shared_ptr的引用循环问题(后文会提到)。
  • 关键接口:
    (1)expired():检查绑定的资源是否已被释放;
    (2)use_count():获取绑定shared_ptr的引用计数;
    (3)lock():返回一个shred_ptr指针(资源未被释放则指向该资源,已经释放则返回空对象),安全访问资源。

3.智能指针的关键问题与解决方法

3.1.shared_ptr的循环引用问题

当两个shared_ptr互相引用时,会形成循环依赖,导致引用计数永远无法减为0,资源无法被成功释放,造成内存泄露。

以双向链表为例:

struct ListNode {
int _data;
shared_ptr<ListNode> _next; // 互相引用shared_ptr<ListNode> _prev;};

初始化两个智能指针变量n1、n2:

shared_ptr<ListNode> n1(new ListNode); // 引用计数=1shared_ptr<ListNode> n2(new ListNode); // 引用计数=1

请添加图片描述
连接两个节点:

n1->_next = n2; // n2引用计数=2
n2->_prev = n1; // n1引用计数=2
// 析构n1和n2时,引用计数各减为1,无法释放资源

请添加图片描述
解决方案:将互相引用的对象改为weak_ptr,通过不增加引用计数,规避掉循环依赖关系。

struct ListNode {
int _data;
weak_ptr<ListNode> _next; // 弱引用,不增加计数weak_ptr<ListNode> _prev;};

3.2.非new资源的释放(删除器)

智能指针默认使用delete释放资源,若管理的是new[]分配的数组、文件指针等非new资源,直接使用会异常。此时需要我们自定义“删除器”,来确保资源能够正常释放。

常用删除器的实现方式:

// 1. 管理new[]数组(推荐:标准库特化版本)
unique_ptr<Date[]> up1(new Date[5]); // 自动用delete[]释放shared_ptr<Date[]> sp1(new Date[5]);// 2. 仿函数作为删除器template<class T>class DeleteArray {public:void operator()(T* ptr) { delete[] ptr; }};unique_ptr<Date, DeleteArray<Date>> up2(new Date[5]);shared_ptr<Date> sp2(new Date[5], DeleteArray<Date>());// 3. lambda作为删除器(管理文件指针)shared_ptr<FILE> sp5(fopen("test.txt", "r"), [](FILE* ptr) {fclose(ptr);});

3.3.线程安全问题

shared_ptr的引用计数本身是线程安全的(标准库实现中使用原子操作),但多线程修改shared_ptr指向的对象时,会访问修改引用计数,此时就会存在线程安全问题,因此shared_ptr引用计数是需要加锁或者原子操作保证线程安全的。

代码示例:多线程修改shared_ptr管理的对象(需要加锁)

#include <iostream>#include <memory>#include <thread>#include <mutex>#include <functional>using namespace std;struct AA {int _a1 = 0;int _a2 = 0;AA() {cout << "AA 构造函数调用:" << this << endl;}~AA() {cout << "AA 析构函数调用:" << this << endl;}};int main() {shared_ptr<AA> p = make_shared<AA>();const size_t loop_count = 100000;mutex mtx;auto func = [&]() {for (size_t i = 0; i < loop_count; ++i) {//智能指针拷贝会++计数shared_ptr<AA> copy(p);unique_lock<mutex> lk(mtx);copy->_a1++;copy->_a2++;}};thread t1(func);thread t2(func);t1.join();t2.join();cout << "最终 _a1 = " << p->_a1 << endl;cout << "最终 _a2 = " << p->_a2 << endl;cout << "当前shared_ptr引用计数 = " << p.use_count() << endl;return 0;}

4.内存泄露的解决方案

4.1.内存泄漏的定义与危害

4.2.如何解决内存泄露问题

  1. 优先使用智能指针管理资源,遵循RAII思想;
  2. 使用工具辅助检测:Linux下的内存泄漏检测工具和Windows下的内存检测工具;
  3. 尽量避免手动new/delete,若必须使用,一定要确保成对出现,且异常场景下能执行释放。

5.C++智能指针的演进关系

  • C++98:推出auto_ptr,存在严重设计缺陷;
  • Boost库:提出scoped_ptr(对应 C++11 的unique_ptr)、shared_ptrweak_ptr,成为 C++11 标准实现更多智能指针的参考;
  • C++11:大量借鉴Boost库中的智能指针设计,正式推出unique_ptrshared_ptrweak_ptr,进一步完善智能指针体系。

结语

智能指针作为 C++11 的内存管理核心工具,彻底革新了动态资源管理方式:无需手动调用new/delete,通过RAII机制自动绑定资源生命周期,让代码更安全可靠;多样的所有权模型(独占 / 共享 / 弱引用)能适配不同场景需求,规避内存泄漏与重复释放,显著降低了开发风险。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1201570.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

汽车自动驾驶的太阳光模拟应用研究 - 详解

汽车自动驾驶的太阳光模拟应用研究 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "…

学术降重必备:AI生成论文工具精选

工具名称 核心优势 适用场景 aicheck 快速降AIGC率至个位数 AIGC优化、重复率降低 aibiye 智能生成论文大纲 论文结构与内容生成 askpaper 文献高效整合 开题报告与文献综述 秒篇 降重效果显著 重复率大幅降低 一站式论文查重降重 查重改写一站式 完整论文优化…

机器人落地“首台套”补贴,到底指什么?

如果你在做机器人创业&#xff0c;一定听过“首台套”补贴。它既不是简单的“第一台设备补贴”&#xff0c;也不是“首台销售额奖励”&#xff0c;而是国家为打通“样机→市场”死亡谷专门设计的一整套政策工具。下面用 3 分钟讲清楚概念、补贴方式、申报要点&#xff0c;以及与…

SQLModel 全面教程:常用 API 串联与实战指南

大家好&#xff0c;我是jobleap.cn的小九。 SQLModel 是一个专为 Python 设计的、融合了 Pydantic 和 SQLAlchemy 优势的 ORM&#xff08;对象关系映射&#xff09;库&#xff0c;它主要用来简化数据库操作与数据校验的流程&#xff0c;解决传统数据库开发中「数据模型定义重复…

SQLModel 全面教程:常用 API 串联与实战指南

大家好&#xff0c;我是jobleap.cn的小九。 SQLModel 是一个专为 Python 设计的、融合了 Pydantic 和 SQLAlchemy 优势的 ORM&#xff08;对象关系映射&#xff09;库&#xff0c;它主要用来简化数据库操作与数据校验的流程&#xff0c;解决传统数据库开发中「数据模型定义重复…

论文写作神器:十大AI辅助工具榜单

工具名称核心优势适用场景aicheck快速降AIGC率至个位数AIGC优化、重复率降低aibiye智能生成论文大纲论文结构与内容生成askpaper文献高效整合开题报告与文献综述秒篇降重效果显著重复率大幅降低一站式论文查重降重查重改写一站式完整论文优化深度AI降重深度改写保留原意文本结构…

谁是 2026 年百度竞价最强服务商?三大实力公司深度对比

2026年百度竞价代运营服务商观察:这三类企业更受客户青睐 在流量成本持续攀升的2026年,百度搜索依然是B2B企业获取高意向客户的重要渠道。然而,随着算法迭代加速、竞争关键词价格翻倍,越来越多中小企业发现:“开了…

2026年度北京回收名家字画机构推荐:这三家高价又靠谱,藏家必看

藏友们好!作为深耕北京古玩收藏圈多年的自媒体人,每年都会收到上百条私信,问得最多的就是“手里有名家字画想变现,哪家机构给价高又不坑人?”2026年北京字画回收市场依旧乱象丛生,虚高报价诱上门、暗箱操作压价、…

苏州 Linux服务器 无法进入系统(Grub Rescue)

序幕&#xff1a;自动化更新的“午夜惊魂”周四凌晨2点17分&#xff0c;万籁俱寂。“智云科技”数据中心的自动化运维系统&#xff0c;正依照既定策略&#xff0c;向数百台服务器推送安全更新补丁。多数服务器安静地完成了任务&#xff0c;唯独那台承载着5TB核心客户画像数据的…

2026年制冷机/气体制冷机/冷热一体机 优选榜单公布

一、行业发展背景及市场现状 在全球能源转型与高端制造业升级的双重推动下,制冷机、气体制冷机、冷热一体机行业迎来高质量发展期,产品技术持续迭代,市场需求多元化升级。据产业世界数据显示,2024年全球制冷设备市…

SQLAlchemy 全面教程:常用 API 串联与实战指南

大家好&#xff0c;我是jobleap.cn的小九。 关于Python 的 SQLAlchemy 组件的核心用途、解决的问题&#xff0c;以及一套系统的实战教程&#xff0c;我会从核心价值到具体 API 再到实战案例&#xff0c;帮你全面掌握这个工具。 一、SQLAlchemy 核心定位&#xff1a;能做什么&am…

LLM知识随笔(二)--BERT

LLM知识随笔&#xff08;二&#xff09;–BERT 文章目录 LLM知识随笔&#xff08;二&#xff09;--BERT一、BERT&#xff1a;公认的里程碑1. BERT与GPT之间的区别&#xff1a;2.单向编码与双向编码的区别 二、BERT的结构&#xff1a;强大的特征提取能力1.ELMo、GPT、BERT三者区…

2026 年百度竞价代运营公司排名公布:TOP3 权威测评来了!

2026 年百度竞价广告迎来全新规则升级,关键词竞价资产前置释放、AI 智能出价模型迭代、质量分考核维度更趋精细化,让粗放式投放彻底失去生存空间,企业想要靠百度竞价精准获客,选对专业的开户代运营服务商成为核心关…

AIGC论文助手:10款智能写作工具盘点

工具名称核心优势适用场景aicheck快速降AIGC率至个位数AIGC优化、重复率降低aibiye智能生成论文大纲论文结构与内容生成askpaper文献高效整合开题报告与文献综述秒篇降重效果显著重复率大幅降低一站式论文查重降重查重改写一站式完整论文优化深度AI降重深度改写保留原意文本结构…

显示器的宽高比一般是多少?什么是屏幕分辨率?常讲的2K 、4K和8K电视是什么含义?

显示器的宽高比指的是屏幕显示画面的宽度与高度的比值&#xff0c;通常以最简整数比的形式表示&#xff0c;标准化比例包括4:3&#xff08;传统标准&#xff09;、16:9(当前主流)和21:9&#xff08;小众特殊比例&#xff09;&#xff0c;它决定了屏幕的整体形状&#xff0c;与分…

在Ubuntu上下载Questasim

仅为本人实操记录,旨在帮助遇到同样问题的友友们。本人小白,所以说的可能比较啰嗦。 用的是VMWare 17Pro,Ubuntu24.04,Questasim10.7c,也是跟着其他人的教程做的,但是过程中出现了很多问题,所以按照我解决之后的…

No.9 监理工作的组织和规划

监理工作的组织和规划 一、监理工作组织和规划总览 &#xff08;一&#xff09;核心意义 通俗解释 监理工作要想干得好&#xff0c;核心得抓两件事&#xff1a;一是“人要靠谱、分工明确”&#xff0c;二是“计划清晰、有章可循”。就像一支施工队&#xff0c;得先确定谁是…

十大AI论文神器:智能降重与高效写作指南

十大AI论文生成工具排行榜&#xff1a;AIGC降重&#xff0c;论文写作生成新选择 工具名称 核心优势 适用场景 aicheck 快速降AIGC率至个位数 AIGC优化、重复率降低 aibiye 智能生成论文大纲 论文结构与内容生成 askpaper 文献高效整合 开题报告与文献综述 秒篇 降…

TAOCP 1.2.1部分习题 - Ghost

TAOCP 1.2.1部分习题 T9 题目标记:[25] 题目: 试求下面式子的求和表达式,并予以证明: \[1^2 , 2^2 -1^2 , 3^2 -2^2 +1^2 , 4^2 -3^2 +2^2 -1^2 \]以下是分析: 手动计算几个,发现就是等差数列求和。 于是我们猜想…

论文降重利器:AI生成工具Top10推荐

工具名称核心优势适用场景aicheck快速降AIGC率至个位数AIGC优化、重复率降低aibiye智能生成论文大纲论文结构与内容生成askpaper文献高效整合开题报告与文献综述秒篇降重效果显著重复率大幅降低一站式论文查重降重查重改写一站式完整论文优化深度AI降重深度改写保留原意文本结构…