当前位置: 首页 > news >正文

《探索C++11:现代语法的内存管理优化“性能指针”(下篇)》

前引:在传统C++开发中,手动内存管理常伴随资源泄漏、悬垂指针等隐患,成为系统稳定性的致命威胁。C++11引入的智能指针体系通过所有权语义自动生命周期管理,从根本上重构了内存安全范式。本文将深入剖析unique_ptrshared_ptrweak_ptr三大核心组件的设计哲学,结合资源所有权转移模型$$ \mathcal{R}(ownership) \rightarrow \mathcal{R}_{smart}(destruction) $$揭示其如何通过编译期契约替代运行时风险,为现代C++工程注入强健性与优雅性!

目录

【一】智能指针定义与用途

(1)定义

(2)用途

【二】智能指针:auto_ptr

【三】智能指针:unique_ptr

【四】智能指针:share_ptr

【五】智能指针:weak_ptr

【六】定制删除器

(1)何为定制删除器

(2)为何使用定制删除器

(3)删除器使用

(4)实现定制删除器


【一】智能指针定义与用途

(1)定义

C++11更新出来的智能指针简而言之就是帮我们解决内存忘记泄漏的问题,它本质上是一个类模板,借助类模板的Delete自动析构函数完成内存的释放。智能指针通过 RAII 机制(weak_ptr除外)管理资源,默认使用delete释放内存!

(2)用途

智能指针主要解决以下几个问题:

(1)忘记手动释放内存

(2)多次释放同一块内存

根据需求的不同,智能指针也有多个,下面一一介绍使用和特性,以及如何手撕!

【二】智能指针:auto_ptr

这个智能指针的设计很不实用,且给我们带来了一定的分担,总体上来说增加了工程Bug,但我们还是要了解一下!

特性:赋值的时候转移资源,很符合移动语义,但这里不是临时对象(将亡值)

例如:有一个A用auto_ptr初始化,当A拷贝给B时,A的资源就给B了,那A就变成空指针了

实现:

template<class T>
class auto_ptr
{
public:auto_ptr(T* ptr):_ptr(ptr){ }auto_ptr(auto_ptr<T>& date){_ptr = date._ptr;date._ptr = nullptr;}~auto_ptr(){delete _ptr;_ptr = nullptr;}T* operator->(){return _ptr;}T& operator*(){return *_ptr;}private:T* _ptr = nullptr;
};

【三】智能指针:unique_ptr

特性:unique单词有唯一的意思,所以这个智能指针会独占资源,即不允许转移资源

实现:

class unique_ptr
{
public:unique_ptr(T* ptr):_ptr(ptr){ }//不让拷贝unique_ptr(const unique_ptr& date) = delete;~unique_ptr(){delete _ptr;_ptr = nullptr;}//不让赋值void operator=(const unique_ptr& date) = delete;T* operator->(){return _ptr;}T& operator*(){return *_ptr;}private:T* _ptr = nullptr;
};

【四】智能指针:share_ptr

特性:share单词有分享的意思,在这里就是同一类型共同拥有一块资源,例如:

实现:

精髓:无论是空间资源指针还是计数空间指针,都采用指向同一块资源的形式

注意:重点是下面的赋值和delete

(1)既然共同占用一块资源,那么在Delete时,应该当是最后一个对象Delete时再释放资源,否           则对同一块资源多次Delete会崩溃

(2)为了确保是最后一个资源我们需要一个计数器:这里采用的是指针,如果是普通整型,那么           当有多个同类对象时无法准确计数,采用静态变量也没有指针形式快捷简单,例如:

template<class T>
class share_ptr
{
public:share_ptr(T* ptr):_ptr(ptr),_count(new int(1)){ }//拷贝构造share_ptr(share_ptr<T>& date){//共同占用资源_ptr = date._ptr;_count = date._count;(*_count)++;}//Delete释放~share_ptr(){//如果是最后一个对象说明可以释放资源了,否则减减_count即可if (*_count == 1){delete _ptr;_ptr = nullptr;delete _count;_count = nullptr;}else{(*_count)--;}}//赋值重载void operator=(share_ptr<T>& date){//如果是自己赋值给自己if (_ptr == date._ptr){return;}//开始共占资源_ptr = date._ptr;*_count++;_count = date._count;}T* operator->(){return _ptr;}T& operator*(){return *_ptr;}private:T* _ptr = nullptr;int* _count = nullptr;
};

效果:

可以看到同类型的share_ptr是共同占用一块资源的,而且delete是根据*_count释放的

【五】智能指针:weak_ptr

特性:weak单词有虚弱的意思,它的“虚”体现在只对资源可以访问,不参与引用计数,专门解决               share_ptr带来的循环引用问题,例如:

           不支持RAII(资源的生命周期与对象的生命周期绑定),不支持单独管理资源

循环引用问题:

循环引用就是share_ptr在初始化前后互相指向的问题(类似:你抓着我的头发,我抱住你的腿,双方都说:“你先放我就放开”),逻辑:

  1. 初始状态a 指向 A 对象(A 的引用计数为 1),b 指向 B 对象(B 的引用计数为 1)。
  2. 互相引用后
    • a->b_ptr = bB 对象的引用计数从 1 变为 2(b 和 a->b_ptr 共同引用)。
    • b->a_ptr = aA 对象的引用计数从 1 变为 2(a 和 b->a_ptr 共同引用)。
  3. main 函数结束时
    • a 离开作用域,A 对象的引用计数从 2 减为 1(剩余 b->a_ptr 引用)。
    • b 离开作用域,B 对象的引用计数从 2 减为 1(剩余 a->b_ptr 引用)。
  4. 最终状态A 和 B 的引用计数都停留在 1(互相引用),永远不会变为 0,因此它们的析构函数不会被调用,内存永远不会释放。

实现:

只是可以访问share_ptr的资源,不参与计数

template<class T>
class weak_ptr
{
public://拷贝构造weak_ptr(share_ptr<T>& date){//共同占用资源_ptr = date.Get();}//赋值重载void operator=(share_ptr<T>& date){//共同占用资源_ptr = date.Get();}T* operator->(){return _ptr;}T& operator*(){return *_ptr;}private:T* _ptr = nullptr;
};

【六】定制删除器

(1)何为定制删除器

在 C++11 中,大部分智能指针通过 RAII 机制管理资源,默认使用delete释放内存。但实际开发中,资源类型远不止动态内存(如文件句柄、网络连接、数组、互斥锁等)这些资源需要特殊的释放逻辑(如fcloseclosedelete[]等)定制删除器(CustomDeleter) 就是为解决这一问题而生的:它允许我们为智能指针指定自定义的资源释放逻辑,让智能指针能够管理任意类型的资源!(简而言之:处理除动态内存之外的释放资源问题)

注:删除器是一个可调用对象(函数指针、lambda、std::function等)

(2)为何使用定制删除器

动态数组需要定制删除器的核心原因是:

(1)动态数组通过 new[] 分配,必须用 delete[] 释放(与 new/delete 不兼容)

(2)智能指针默认使用 delete 释放资源,与数组的释放要求冲突

(3)定制删除器可以显式指定 delete[],确保分配与释放逻辑匹配,避免内存泄漏或未定义行为

(3)删除器使用

传仿函数:

template<class T>
struct Function
{void operator()(T* ptr){delete[] ptr;ptr = nullptr;}
};
shared_ptr<string> V1(new string[10],Function<string>());

传Lambda:

shared_ptr<string> V2(new string[10], [](string* ptr) { delete[] ptr; ptr = nullptr; });

文件释放:

shared_ptr<FILE> V3(fopen("text.cpp", "c"), [](FILE* ptr) {fclose(ptr); });
(4)实现定制删除器
template<class T>
class share_ptr
{
public:share_ptr(T* ptr):_ptr(ptr),_count(new int(1)){ }//定制删除器template<class D>share_ptr(T* ptr,D del):_ptr(ptr),_count(new int(1)),_del(del){}//拷贝构造share_ptr(share_ptr<T>& date){//共同占用资源_ptr = date._ptr;_count = date._count;(*_count)++;}//Delete释放~share_ptr(){//如果是最后一个对象说明可以释放资源了,否则减减_count即可if (*_count == 1){_del = _ptr;delete _count;_count = nullptr;}else{(*_count)--;}}//赋值重载void operator=(share_ptr<T>& date){//如果是自己赋值给自己if (_ptr == date._ptr){return;}//开始共占资源_ptr = date._ptr;*_count++;_count = date._count;}T* operator->(){return _ptr;}T& operator*(){return *_ptr;}T* Get(){return _ptr;}private:T* _ptr = nullptr;int* _count = nullptr;function<void(T*)> _del = [](T* ptr) {delete ptr; };
};


文章转载自:

http://Kdha6uiW.gjqwt.cn
http://Q06YFnab.gjqwt.cn
http://Nb2mcakP.gjqwt.cn
http://XZBdzozg.gjqwt.cn
http://0RUwCcvz.gjqwt.cn
http://SzTdUDui.gjqwt.cn
http://Kb8rdy84.gjqwt.cn
http://mCuEi92w.gjqwt.cn
http://WRQimwTe.gjqwt.cn
http://zJuiwQEL.gjqwt.cn
http://6dwdH8yz.gjqwt.cn
http://740toq6F.gjqwt.cn
http://WlMYzUH1.gjqwt.cn
http://QPttcSkP.gjqwt.cn
http://aqxighFn.gjqwt.cn
http://DKKX2FED.gjqwt.cn
http://rsFVHdTs.gjqwt.cn
http://n98yN0OU.gjqwt.cn
http://GaCIVrKk.gjqwt.cn
http://hwgEHDt0.gjqwt.cn
http://gQXdzQt5.gjqwt.cn
http://lXB2ZfjC.gjqwt.cn
http://Y9P2NoUR.gjqwt.cn
http://isvhrKyB.gjqwt.cn
http://t0XoMTx6.gjqwt.cn
http://8kCPCGZN.gjqwt.cn
http://nOAPji0P.gjqwt.cn
http://XDpCHs8m.gjqwt.cn
http://G6LAzqJZ.gjqwt.cn
http://cVfyAmw5.gjqwt.cn
http://www.dtcms.com/a/372201.html

相关文章:

  • Basic Pentesting: 1靶场渗透
  • NAS自建笔记服务leanote2
  • 对比Java学习Go——程序结构与变量
  • 【JavaWeb】一个简单的Web浏览服务程序
  • [C/C++学习] 7.“旋转蛇“视觉图形生成
  • webhook(Web 钩子)是什么?
  • 《2025年AI产业发展十大趋势报告》四十三
  • java面试小册(1)
  • NW506NW507美光固态闪存NW525NW539
  • [Maven 基础课程]再看下第一个 Maven 项目
  • Keil快捷键代码补全
  • 2024理想算法岗笔试笔记
  • Java面试-线程安全篇
  • 线程池深度解析:ThreadPoolExecutor底层实现与CompletableFuture异步编程实战
  • 计算机网络学习(七、网络安全)
  • 蓝奏云官方版不好用?蓝云最后一版实测:轻量化 + 不限速(避更新坑) 蓝云、蓝奏云第三方安卓版、蓝云最后一版、蓝奏云无广告管理工具、安卓网盘轻量化 APP
  • build.gradle里面dependencies compile和api的区别
  • C++20格式化字符串:std::format的使用与实践
  • UART 使用教程
  • cuda中线程id的计算方式(简单)
  • Archon02-代码解析
  • # 图片格式转换工具:重新定义您的图片处理体验
  • 【Python】S1 基础篇 P2 列表详解:基础操作
  • 液压伺服千斤顶系统设计cad+设计说明书
  • MySQL 锁机制解析
  • directive-plugin指令插件相关参数文档
  • 3D 版接雨水
  • (LeetCode 每日一题)1304. 和为零的 N 个不同整数(数组)
  • WebGL2初识
  • 浏览器兼容性问题全解:CSS 前缀、Grid/Flex 布局兼容方案与跨浏览器调试技巧