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

【C++】智能指针

目录

一、先来看一下什么是智能指针

二、 auto_ptr

 1、C++98版本

2、C++11的auto_ptr

三、boost 库中的智能指针

1. scoped_ptr

2、shared_ptr(最好的智能指针)

四、C++11中新提供的智能指针

unique_ptr  

shared_ptr

std::shared_ptr的循环引用问题

weak_ptr弱指针

 shared_ptr 定制删除器  (智能指针真强大!!!)


一、先来看一下什么是智能指针

 智能:        可以看到我们在申请资源之后并没有进行手动释放但是却没有内存的泄漏

 指针:        他明明是个对象,但用起来却像指针一样

可以发现,智能指针是很神奇的,下面让我们来看看他是怎样做到这些的吧

二、 auto_ptr

 1、C++98版本

原理如下:类中含有两个成员

模拟:

C++98有着很大的缺陷,主要就是拥有权的问题

当拥有权转移之后,原来的还能去访问到数据,这显然是一种藕断丝连的现象

 这就导致了一种错觉,仿佛转移之后还拥有着使用权

2、C++11的auto_ptr

我们来看看C++11对这种现象是怎么处理的

 我们可以发现C++11就改进了这一点,不存在藕断丝连这一说了

三、boost 库中的智能指针

1. scoped_ptr

这个指针是个局部智能指针,就像个“貔貅”一样,只进不出,不允许拥有权的转移,构造拷贝都无法进行,底层是一个普通的指针

 模拟实现:

template<class T>
class scoped_ptr
{
public:scoped_ptr(T* p = 0) : px(p){}~scoped_ptr(){//检查释放//boost::checked_delete( px );delete px;}
public:T& operator*() const{return *px;}T* operator->() const{return px;}T* get() const{return px;}
public:typedef scoped_ptr<T> this_type;void reset(T* p = 0){//构造一个无名临时对象this_type(p).swap(*this);//this_type(p)  ==> scoped_ptr<T>(p);}void swap(scoped_ptr& b) // never throws{T* tmp = b.px;b.px = px;px = tmp;}
private:scoped_ptr(scoped_ptr const&);scoped_ptr& operator=(scoped_ptr const&);  //私有的设置,不允许拷贝,赋值void operator==(scoped_ptr const&) const;void operator!=(scoped_ptr const&) const;
private:T* px;
};

2、shared_ptr(最好的智能指针)

底层原理图:内部是有一个引用计数器

引用计数器和之前学过的写实拷贝的地方实现原理很相似

功能:     允许拷贝,赋值   还可以输出有几个引用

 

 

模拟实现:

实现这个shared_ptr 智能指针  需要有四个类

1.   class shared_ptr类


#include"shared_count.h"namespace zyf
{template<class T>class shared_ptr{typedef shared_ptr<T> this_type;public:shared_ptr():px(0){}template<class Y>shared_ptr(Y* p) : px(p), pn(p){
#ifdef DISPLAYcout << "Created shread_ptr obj." << endl;
#endif}~shared_ptr(){
#ifdef DISPLAYcout << "Free shread_ptr obj." << endl;
#endif}shared_ptr& operator=(const shared_ptr& r){this_type(r).swap(*this);return *this;}shared_ptr(const shared_ptr<T> &r):px(r.px),pn(r.pn){}public:long use_count()const{return pn.use_count();}public:T& operator*()const{return *px;}public:void swap(shared_ptr<T>& other){std::swap(px, other.px);pn.swap(other.pn);}private:T* px;shared_count pn;//引用计数器对象};
}

2.   shared_count 类

//引用计数器类
class shared_count
{
public:shared_count():pi_(0){}template<class Y>shared_count(Y *p):pi_(0){pi_ = new sp_counted_impl<Y>(p);//多态
#ifdef DISPLAYcout << "Created shread_count obj." << endl;
#endif}~shared_count(){
#ifdef DISPLAYcout << "Free shread_count obj." << endl;
#endifif (pi_)pi_->release();}shared_count(const shared_count& r):pi_(r.pi_){if (pi_ != 0)pi_->add_ref_copy();}public:long use_count()const{if (pi_ == nullptr)return 0;return pi_->use_count();		}
public:void swap(shared_count& r){sp_counted_base* tmp = r.pi_;r.pi_ = pi_;pi_ = tmp;}
private:sp_counted_base* pi_;
};

3.   sp_counted_base类

class sp_counted_base
{
public:sp_counted_base() :use_count_(1){
#ifdef DISPLAYcout << "Created sp_counted_base obj" << endl;
#endif}virtual ~sp_counted_base(){
#ifdef  DISPLAYcout << "Free sp_counted_base obj" << endl;
#endif}
public:void add_ref_copy(){use_count_++;}void release(){if (--use_count_ == 0){delete this;}}long use_count()const{return use_count_;}
private:long use_count_;};

4.sp_counted_impl类  ,这个类是继承  sp_sounted_base 类的

#include"sp_counted_base.h"template<class X>
class sp_counted_impl : public sp_counted_base
{
public:sp_counted_impl(X *px):px_(px){
#ifdef DISPLAYcout << "Created sp_sounted_impl obj." << endl;
#endif}~sp_counted_impl(){delete px_;
#ifdef DISPLAYcout << "Free sp_sounted_impl obj." << endl;
#endif}
private:X* px_;
};

四、C++11中新提供的智能指针

unique_ptr  

和scoped_ptr  一样 ,不允许拥有权的转移,和“貔貅”一样

shared_ptr

std::shared_ptr的线程安全问题

这里的线程不安全问题和之前的黄牛抢票现象是一样的:

 

std::shared_ptr的循环引用问题

这里我们用一个双向列表的例子来举例说明什么是循环引用

我们先只创建两个节点类型,观察一下情况会是什么样子的。

 我们发现,构造和析构函数能够正确的被调用,没有出现问题

这时候我们再来将这两个节点连接起来,观察一下会是怎么样的

 我们很神奇的发现,不连还好,一连就出问题,析构函数没有被调用,这是什么情况呢?我们来探究一下

 在函数调用结束后释放node1和node2智能指针所指向的资源的时候会给两个资源的计数器都减减,但是也只是减为1,两个节点内部的指针相互指向,到最后谁都释放不了。

根本原因:

  节点相互连接赋值的时候,因为内部的prev和 next 和节点的 node类型是一种类型,导致引用计数器会增加,

weak_ptr弱指针

解决这里的办法就是使用weak_ptr

weak_ptr 是为配合 shared ptr 而引入的一种智能指针,它更像是 shared ptr 的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载 operator*和->。它的最大作用在于协助 shared ptr 工作,像旁观者那样观测资源的使用情况。

上面我们知道了,使用weak_ptr 可以不增加引用计数 

使用了weak_ptr之后我们再来看看会是怎么样的

 

 shared_ptr 定制删除器  (智能指针真强大!!!)

只要共享性智能指针对象的释放方式不能满足我们的要求,我们就可以取定制一个

1.  遇到数组类型的空间

 这时候可以定制一个删除器

 这时候就解决问题了

 

 2. 还可以解决不是new 出来的空间问题

比如是malloc出来的,这时候应该用free去对应

 

其他问题也可以:  比如是文件描述符:  socketfd  、 newsockfd 、fp

 

相关文章:

【C++】智能指针

目录 一、先来看一下什么是智能指针 二、 auto_ptr 1、C98版本 2、C11的auto_ptr 三、boost 库中的智能指针 1. scoped_ptr 2、shared_ptr&#xff08;最好的智能指针&#xff09; 四、C11中新提供的智能指针 unique_ptr shared_ptr std::shared_ptr的循环引用问题…...

Seata架构篇 - AT模式

AT 模式 概述 Seata AT 模式是一种非侵入式的分布式事务解决方案&#xff0c;Seata 在内部做了对数据库操作的代理层&#xff0c;我们使用 Seata AT 模式时&#xff0c;实际上用的是 Seata 自带的数据源代理 DataSourceProxy&#xff0c;Seata 在这层代理中加入了很多逻辑&am…...

加油站会员管理小程序实战开发教程12

我们上一篇介绍了会员数据源的开发,本节我们介绍一下会员注册功能。 首先呢梳理一下会员注册的业务逻辑,如果用户是首次登录,那他肯定还没有给我们的小程序提交任何的信息。那么我们就在我的页面给他显示一个注册的按钮,如果他已经注册过了,那么就正常显示会员的信息,他…...

用腾讯云同步Obsidian笔记

介绍 之前用gitee同步OB笔记&#xff0c;同时做图床。但由于git系产品设置起来相对复杂&#xff0c;且后续可能有外链过审等问题。周五被同事小姐姐安利了用腾讯云COS&#xff0c;试了一下&#xff0c;果然不错。其主要优点如下&#xff1a; 设置简单&#xff0c;学习成本低&…...

浅析C++指针与引用,栈传递的关系

目录 前言 C 堆指针 栈指针 常量指针 指针常量 引用 常量引用 总结 前言 目前做了很多项目&#xff0c;接触到各种语言&#xff0c;基本上用什么学什么&#xff0c;语言的边际就会很模糊&#xff0c;实际上语言的设计大同小异&#xff0c;只是语言具备各自的特性区别。…...

图解LeetCode——剑指 Offer 10- II. 青蛙跳台阶问题

一、题目 一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。 答案需要取模 1e97&#xff08;1000000007&#xff09;&#xff0c;如计算初始结果为&#xff1a;1000000008&#xff0c;请返回 1。 二、示例 2.1>…...

【Linux】用户分类+权限管理+umask+粘滞位说明

目录 1.用户分类 su指令 2.认识Linux权限 2.1 文件访问者的分类 2.2 文件类型和访问权限 a. 文件类型 file指令 b. 访问权限 2.3 文件权值的表示方法 a. 字母表示法 b. 八进制表示法 3.如何修改文件访问者的权限及相关指令 1. chmod指令 2. chown指令 3. chgrp指…...

【干货】如何打造HR无法拒绝的简历?测试开发大牛带手把手你写简历!

通过率90%&#xff0c;优秀的软件测试简历长什么样&#xff1f; 也许口才好的人会觉得简历不重要&#xff0c;能说就行了&#xff0c;那是因为你没有体会过石沉大海的感觉&#xff01; 很多人觉得疑惑&#xff0c;为什么我投了那么多简历&#xff0c;都没有接到面试通知&…...

nodejs学习-4:nodejs连接mongodb和相关操作

1. express生成器生成express模板 前提需要首先下载好&#xff1a;express-generator&#xff0c;命令如下(全局安装) npm install -g express-generator生成模板命令如下&#xff1a; express 项目名称 --viewejs // --view 参数表示前端界面使用的引擎&#xff0c;这里使用…...

【博客629】Linux DNS解析原理与配置

Linux DNS解析原理与配置 1、DNS缓存 作用&#xff1a; 程序客户端、下游的 DNS 服务器每次查询 DNS 成功之后&#xff0c;通常会将该 DNS 记录缓存一段时间&#xff0c;避免频繁发出查询请求的耗时。 Linux下的DNS缓存&#xff1a; Linux 系统默认不会在本地建立 DNS 缓存…...

【CSP】202212-2 训练计划

题目 问题背景 西西艾弗岛荒野求生大赛还有 天开幕&#xff01; 问题描述 为了在大赛中取得好成绩&#xff0c;顿顿准备在 天时间内完成“短跑”、“高中物理”以及“核裂变技术”等总共 项科目的加强训练。其中第 项&#xff08; &#xff09;科目编号为 &#xff0c;也可简…...

java基础学习 day42(继承中构造方法的访问特点,this、super的使用总结)

继承中&#xff0c;构造方法的访问特点 父类的构造方法不会被子类继承&#xff0c;但可以通过super()调用父类的构造方法&#xff0c;且只能在子类调用&#xff0c;在测试类中是不能手动单写构造方法的。子类中所有的构造方法默认先调用父类的无参构造&#xff0c;再执行自己构…...

生物医药多组学与生物信息方法介绍

基因组学告诉你可能发生什么&#xff0c;转录组学和蛋白组学告诉你即将发生什么&#xff0c;而代谢组学告诉你正在发生什么 1、多组学与生信方法 生物医学技术的组学包括基因组学、转录组学、蛋白质组学、代谢组学和表观基因组学等。这些组学研究领域通过大量数据的高通量技术…...

3|物联网控制|计算机控制-刘川来胡乃平版|第2章:计算机控制系统中的检测设备和执行机构-2.2过程控制中常用的执行器|课堂笔记|ppt

...

【进阶篇】线程的硬件基础

文章目录高速缓存缓存一致性协议写缓冲区和无效化队列高速缓存 简介 高速缓存是主内存与处理器之间的硬件&#xff0c;其容量小于主存&#xff0c;但存取速率远高于主存。因此处理器在执行读写操作时&#xff0c;可直接和高速缓存交互&#xff0c;提高响应速度。 我们常见的变…...

关于 ISP Tuning的学习,分享几点看法

关于学习&#xff0c;分享几点看法&#xff0c;欢迎讨论 。1、分阶段性的&#xff0c;阶梯式学习。2、带目的性的&#xff0c;任务式学习。3、有总结性的&#xff0c;输出式学习。如上3条&#xff0c;可以依次循环去执行&#xff0c;下面我以 ISP Tuning 的学习为例&#xff0c…...

RocketMQ源码阅读

没有用过rocketmq&#xff0c;但是一直对RocketMQ的实现很感兴趣&#xff0c;本次阅读源码基于5.0.0 一、 nameserver 通过源码阅读发现&#xff0c;它的作用主要是当作一个注册中心&#xff0c;注册broker、topic等信息&#xff0c;维护topic以及broker队列的路由信息&#…...

重磅 | 小O软件新品【鲸鱼地图】发布

千呼万唤始出来.......&#xff0c;小O系列软件又添新品【鲸鱼地图】&#xff01;&#xff01;&#xff01; 2023年新年伊始&#xff0c;小O就投入到新品研发工作中&#xff0c;秉承“发现地理价值”理念&#xff0c;为用户提供更加好用、易用的地图软件产品&#xff0c;经过春…...

软考高级信息系统项目管理师系列之二十五:项目合同管理

软考高级信息系统项目管理师系列之二十五:项目合同管理 一、项目合同管理内容整理一、合同管理基本概念1.项目合同管理定义2.合同的分类3.合同类型选择4.合同内容二、合同管理过程1.合同管理过程的内容2.合同签订和履行管理3.合同变更和档案管理4.合同违约索赔管理项目合同管理…...

测试开发之Django实战示例 第十三章 上线

在上一章&#xff0c;为其他程序与我们的Web应用交互创建了RESTful API。本章将学习如何创建生产环境让我们的网站正式上线&#xff0c;主要内容有&#xff1a;配置生产环境创建自定义中间件实现自定义管理命令1创建生产环境现在该将Django项目正式部署到生产环境中了。我们将按…...

杰理之似于“PO”声,如果切换的时机刚好在音量较高的时候,比较容易出现【篇】

似于“PO”声&#xff0c;如果切换的时机刚好在音量较高的时候&#xff0c;比较容易出现...

从几何视角解析单层感知机:超平面、分类与学习算法

1. 单层感知机&#xff1a;从几何空间看分类本质 第一次接触单层感知机时&#xff0c;很多人会被各种数学符号绕晕。其实换个角度看&#xff0c;它就是个拿着尺子在高维空间里画分界线的工具。想象你面前有一堆红蓝两色的气球&#xff0c;单层感知机要做的&#xff0c;就是找到…...

终极营销自动化工作流设计:工程师如何构建高效营销流程

终极营销自动化工作流设计&#xff1a;工程师如何构建高效营销流程 【免费下载链接】Marketing-for-Engineers A curated collection of marketing articles & tools to grow your product. 项目地址: https://gitcode.com/gh_mirrors/ma/Marketing-for-Engineers …...

【初阶数据结构】 左右逢源的分支诗律 二叉树1

&#x1f4d6; 点击展开/收起 文章目录 文章目录树的概念***树的基础概念***森林树和森林的存储二叉树二叉树的性质二叉树的遍历二叉树的前序遍历二叉树的中序遍历二叉树的后序遍历希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力&#xff01;树的概念 在讲解…...

基于ChatGee框架的KakaoTalk ChatGPT机器人部署与定制指南

1. 项目概述&#xff1a;一个为KakaoTalk量身定制的ChatGPT机器人 如果你在韩国工作、生活&#xff0c;或者你的用户群体主要在韩国&#xff0c;那么KakaoTalk&#xff08;카카오톡&#xff09;这款国民级即时通讯应用&#xff0c;你一定不陌生。它几乎覆盖了韩国所有的智能手…...

透视 Mission Control 源码:如何构建高性能的 Agent 实时监控架构?

在 AI Agent 爆火的当下&#xff0c;我们正从“对话式 AI”迈向“行为式 AI”。然而&#xff0c;当数十个 Agent 同时运行&#xff0c;处理复杂的链上交易或长程任务时&#xff0c;开发者面临的最大挑战往往是&#xff1a;观测性&#xff08;Observability&#xff09;。你无法…...

什么是大模型:概念、分类与当前主流模型全梳理

什么是大模型&#xff1f; 大模型&#xff0c;通常指的是参数规模很大、训练数据很多、具备较强通用能力的人工智能模型。它之所以叫“大”&#xff0c;通常体现在几个方面&#xff1a; 第一&#xff0c;参数量大。 从早期的几千万、几亿参数&#xff0c;发展到几十亿、上百亿&…...

告别内网穿透:OpenWrt软路由IPv6配置实战与DDNS部署指南

1. 为什么我们需要IPv6&#xff1f; 最近几年&#xff0c;越来越多的朋友发现家里的宽带已经拿不到IPv4公网地址了。我自己用的移动宽带就是这样&#xff0c;光猫改桥接后用软路由拨号&#xff0c;拿到的永远是个100开头的内网IP。打电话给运营商&#xff0c;客服很客气地告诉我…...

别再让延迟搞砸你的PID控制!手把手教你用Matlab Simulink搭建Smith预估器(附完整模型)

从PID震荡到稳定控制&#xff1a;Matlab Simulink中Smith预估器的实战集成指南 当你精心设计的PID控制器在仿真中突然开始疯狂振荡&#xff0c;屏幕上那条曲线像喝醉了一样左右摇摆时&#xff0c;延迟问题很可能就是罪魁祸首。这不是算法本身的问题&#xff0c;而是现实世界中执…...

别再死记硬背了!我用700多页图解八股文,帮你把Java面试考点画成故事

用视觉叙事重构Java面试&#xff1a;700页图解背后的认知科学实践 翻开任何一本Java面试指南&#xff0c;你大概率会看到密密麻麻的文字罗列——"JVM内存结构分为哪几部分&#xff1f;""Synchronized和ReentrantLock有什么区别&#xff1f;"这些被称为&quo…...