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

【C++】12.智能指针

在上一篇博客【C++】11.异常中我们知道有些时候会造成内存空间的未释放从而导致内存泄漏,因此本篇博客的内容就是如何减少内存泄漏——智能指针。

一、RAII

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源的简单技术,因此又被称为资源获取即初始化
本质上就是在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:

  • 不需要显式地释放资源。
  • 采用这种方式,对象所需的资源在其生命期内始终保持有效。

下面这段程序就是使用RAII思想构造的智能指针的底板:

template<class T>
class SmartPtr
{
public:SmartPtr(T* ptr=nullptr):_ptr(ptr){}~SmartPtr(){if(_ptr)delete _ptr;}
private:T* _ptr;
};

二、智能指针的原理

上述的SmartPtr还不能将其称为智能指针,因为它还不具有指针的行为。指针可以解引用,也可以通过->去访问所指空间中的内容,因此:SmartPtr模板类中还得需要将* 、->重载下,才可让其像指针一样去使用。

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

三、智能指针的发展

3.1 auto_ptr

C++98版本的库中就提供了auto_ptr的智能指针。下面演示的auto_ptr的使用及问题。
auto_ptr的实现原理:管理权转移的思想,下面简化模拟实现了一份auto_ptr来了解它的原理,并不建议使用

namespace caryon
{template<class T>class auto_ptr{public:auto_ptr(T* ptr = nullptr) :_ptr(ptr) {}auto_ptr(auto_ptr& ap):_ptr(ap._ptr){ap._ptr = nullptr;}auto_ptr& operator=(auto_ptr& ap){if(_ptr!=ap._ptr){if(_ptr=nullptr)delete _ptr;_ptr = ap._ptr;ap._ptr = nullptr;}return *this;}~auto_ptr(){if (_ptr)delete _ptr;}T* operator->(){return _ptr;}T& operator*(){return *_ptr;}private:T* _ptr;};
}

3.2 unique_ptr

C++11中开始提供更靠谱的unique_ptr
unique_ptr的实现原理:简单粗暴的防拷贝,下面简化模拟实现了一份unique_ptr来了解它的原理

namespace caryon
{template<class T>class unique_ptr{public:unique_ptr(T* ptr = nullptr) :_ptr(ptr) {}unique_ptr(unique_ptr& ap) = delete;unique_ptr& operator=(unique_ptr& ap) = delete;~unique_ptr(){if (_ptr)delete _ptr;}T* operator->(){return _ptr;}T& operator*(){return *_ptr;}private:T* _ptr;};
}

3.3 shared_ptr

C++11中开始提供更靠谱的并且支持拷贝的shared_ptr
shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源

  1. shared_ptr在其内部,给每个资源都维护着一份计数,用来记录该份资源被几个对象共享。
  2. 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。
  3. 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
  4. 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。
namespace caryon
{template<class T>class shared_ptr{public:shared_ptr(T* ptr = nullptr) :_ptr(ptr),_pcount(new int(1)) {}shared_ptr(shared_ptr& sp):_ptr(sp._ptr),_pcount(sp._pcount){(*_pcount)++;}shared_ptr& operator=(shared_ptr& sp){if(_ptr!=sp._ptr){~shared_ptr();shared_ptr(sp);}return *this;}~shared_ptr(){--(*_pcount);if (*_pcount==0){delete _ptr;delete _pcount;}}T* operator->(){return _ptr;}T& operator*(){return *_ptr;}private:T* _ptr;int* _pcount;};
}

循环引用

struct ListNode
{size_t val;caryon::shared_ptr<ListNode> _prev;caryon::shared_ptr<ListNode> _next;~ListNode(){cout << "~ListNode()" << endl;}
};
int main()
{caryon::shared_ptr<ListNode> n1(new ListNode);caryon::shared_ptr<ListNode> n2(new ListNode);n1->_next = n2;n2->_prev = n1;return 0;
}

在这里插入图片描述
这样的情况就有了weak_ptr

3.4 weak_ptr

namespace caryon
{template<class T>class weak_ptr{public:weak_ptr(){}weak_ptr(const shared_ptr<T>& sp):_ptr(sp.get()){}weak_ptr<T>& operator=(const shared_ptr<T>& sp){_ptr = sp.get();return *this;}private:T* _ptr = nullptr;};
}

四、C++11和boost的关系

  1. C++ 98 中产生了第一个智能指针auto_ptr
  2. C++ boost给出了更实用的scoped_ptr和shared_ptr和weak_ptr
  3. C++ TR1,引入了shared_ptr等。不过注意的是TR1并不是标准版。
  4. C++ 11,引入了unique_ptr和shared_ptr和weak_ptr。需要注意的是unique_ptr对应boost的scoped_ptr。并且这些智能指针的实现原理是参考boost中的实现的。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Jupyter Notebook 使用多个Kernel
  • 技术文档索引
  • Linux 内核源码分析---组播/策略路由选择
  • 内存函数memcpy和memmove
  • 谷歌chrome浏览器显示“版本太旧”又无法更新情况下,如何关闭“Chrome版本太旧”提示,包括直接启动Google浏览器,或者通过其他应用启动
  • Web层统一实体规范封装
  • 出现 2003 - Can’t connect to MySQL server on ‘xxx‘(10060) 解决方法
  • 3b1b自注意力机制讲解记录
  • 3、springboot时代背景
  • Variomes:支持基因组变异筛选的高召回率搜索引擎
  • 0基础深度学习项目13:基于TensorFolw实现天气识别
  • JavaScript初级——DOM和事件简介
  • 递归神经网络 (RNN) 简介
  • 【微信小程序】自定义组件 - behaviors
  • 微服务:配置管理和配置热更新
  • 「面试题」如何实现一个圣杯布局?
  • 08.Android之View事件问题
  • Docker下部署自己的LNMP工作环境
  • es6--symbol
  • linux安装openssl、swoole等扩展的具体步骤
  • node学习系列之简单文件上传
  • Spring思维导图,让Spring不再难懂(mvc篇)
  • Tornado学习笔记(1)
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • vue-router的history模式发布配置
  • 多线程 start 和 run 方法到底有什么区别?
  • 技术:超级实用的电脑小技巧
  • 漂亮刷新控件-iOS
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 入口文件开始,分析Vue源码实现
  • 事件委托的小应用
  • 思考 CSS 架构
  • 微信开源mars源码分析1—上层samples分析
  • 用简单代码看卷积组块发展
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • postgresql行列转换函数
  • ​​​​​​​STM32通过SPI硬件读写W25Q64
  • ​flutter 代码混淆
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • ‌JavaScript 数据类型转换
  • #laravel 通过手动安装依赖PHPExcel#
  • #微信小程序:微信小程序常见的配置传值
  • (14)Hive调优——合并小文件
  • (31)对象的克隆
  • (vue)页面文件上传获取:action地址
  • (WSI分类)WSI分类文献小综述 2024
  • (阿里巴巴 dubbo,有数据库,可执行 )dubbo zookeeper spring demo
  • (多级缓存)缓存同步
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (六)Flink 窗口计算
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (五)Python 垃圾回收机制
  • (一)kafka实战——kafka源码编译启动
  • .chm格式文件如何阅读
  • .NET 简介:跨平台、开源、高性能的开发平台