当前位置: 首页 > 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://www.xdnf.cn/news/1486675.html

相关文章:

  • LeetCode 面试经典 150 题:移除元素(双指针思想优化解法详解)
  • RICOH理光 Priport DX4443c速印机 印A3的问题
  • 数据结构之二叉树(2)
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘setuptools’问题
  • 嵌入式学习---(ARM)
  • AutoHotkey将脚本编译为exe文件
  • DevOps实战(3) - 使用Arbess+GitLab+Hadess实现Java项目自动化部署
  • 【Java基础|第三十五篇】类加载与反射
  • 如何在Python中使用正则表达式?
  • 基于Apache Flink Stateful Functions的事件驱动微服务架构设计与实践指南
  • Flink TaskManager日志时间与实际时间有偏差
  • 鱼眼相机模型
  • JVM-默背版
  • 实验室服务器配置|通过Docker实现Linux系统多用户隔离与安全防控
  • Flink NetworkBufferPool核心原理解析
  • Android --- SystemUI 导入Android Studio及debug
  • 2025年体制内职业发展相关认证选择指南
  • 超越自动补全:将AI编码助手深度集成到你的开发工作流​​
  • 微信小程序中实现AI对话、生成3D图像并使用xr-frame演示
  • C++ 连接 Redis:redis-plus-plus 安装与使用入门指南
  • 关于npm的钩子函数
  • 【iOS】push,pop和present,dismiss
  • 上架商品合规流程有多条,有的长,有的短,有的需要审核,校验商品的合规性
  • RestTemplate使用 | RestTemplate设置http连接池参数
  • axios的两种异步方式对比
  • K8S-Pod(下)
  • 笔记本、平板如何成为电脑拓展屏?向日葵16成为副屏功能一键实现
  • python---静态方法和类方法
  • Python学习——安装配置python环境+入门
  • Onecode 可视化动作揭秘系列二:组件类型个性化配置技术协议