【C++】智能指针
目录
一、先来看一下什么是智能指针
二、 auto_ptr
1、C++98版本
2、C++11的auto_ptr
三、boost 库中的智能指针
1. scoped_ptr
四、C++11中新提供的智能指针
unique_ptr
weak_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(最好的智能指针) 四、C11中新提供的智能指针 unique_ptr shared_ptr std::shared_ptr的循环引用问题…...

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

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

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

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

图解LeetCode——剑指 Offer 10- II. 青蛙跳台阶问题
一、题目 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。 答案需要取模 1e97(1000000007),如计算初始结果为:1000000008,请返回 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%,优秀的软件测试简历长什么样? 也许口才好的人会觉得简历不重要,能说就行了,那是因为你没有体会过石沉大海的感觉! 很多人觉得疑惑,为什么我投了那么多简历,都没有接到面试通知&…...

nodejs学习-4:nodejs连接mongodb和相关操作
1. express生成器生成express模板 前提需要首先下载好:express-generator,命令如下(全局安装) npm install -g express-generator生成模板命令如下: express 项目名称 --viewejs // --view 参数表示前端界面使用的引擎,这里使用…...
【博客629】Linux DNS解析原理与配置
Linux DNS解析原理与配置 1、DNS缓存 作用: 程序客户端、下游的 DNS 服务器每次查询 DNS 成功之后,通常会将该 DNS 记录缓存一段时间,避免频繁发出查询请求的耗时。 Linux下的DNS缓存: Linux 系统默认不会在本地建立 DNS 缓存…...
【CSP】202212-2 训练计划
题目 问题背景 西西艾弗岛荒野求生大赛还有 天开幕! 问题描述 为了在大赛中取得好成绩,顿顿准备在 天时间内完成“短跑”、“高中物理”以及“核裂变技术”等总共 项科目的加强训练。其中第 项( )科目编号为 ,也可简…...

java基础学习 day42(继承中构造方法的访问特点,this、super的使用总结)
继承中,构造方法的访问特点 父类的构造方法不会被子类继承,但可以通过super()调用父类的构造方法,且只能在子类调用,在测试类中是不能手动单写构造方法的。子类中所有的构造方法默认先调用父类的无参构造,再执行自己构…...
生物医药多组学与生物信息方法介绍
基因组学告诉你可能发生什么,转录组学和蛋白组学告诉你即将发生什么,而代谢组学告诉你正在发生什么 1、多组学与生信方法 生物医学技术的组学包括基因组学、转录组学、蛋白质组学、代谢组学和表观基因组学等。这些组学研究领域通过大量数据的高通量技术…...

【进阶篇】线程的硬件基础
文章目录高速缓存缓存一致性协议写缓冲区和无效化队列高速缓存 简介 高速缓存是主内存与处理器之间的硬件,其容量小于主存,但存取速率远高于主存。因此处理器在执行读写操作时,可直接和高速缓存交互,提高响应速度。 我们常见的变…...
关于 ISP Tuning的学习,分享几点看法
关于学习,分享几点看法,欢迎讨论 。1、分阶段性的,阶梯式学习。2、带目的性的,任务式学习。3、有总结性的,输出式学习。如上3条,可以依次循环去执行,下面我以 ISP Tuning 的学习为例,…...
RocketMQ源码阅读
没有用过rocketmq,但是一直对RocketMQ的实现很感兴趣,本次阅读源码基于5.0.0 一、 nameserver 通过源码阅读发现,它的作用主要是当作一个注册中心,注册broker、topic等信息,维护topic以及broker队列的路由信息&#…...

重磅 | 小O软件新品【鲸鱼地图】发布
千呼万唤始出来.......,小O系列软件又添新品【鲸鱼地图】!!! 2023年新年伊始,小O就投入到新品研发工作中,秉承“发现地理价值”理念,为用户提供更加好用、易用的地图软件产品,经过春…...
软考高级信息系统项目管理师系列之二十五:项目合同管理
软考高级信息系统项目管理师系列之二十五:项目合同管理 一、项目合同管理内容整理一、合同管理基本概念1.项目合同管理定义2.合同的分类3.合同类型选择4.合同内容二、合同管理过程1.合同管理过程的内容2.合同签订和履行管理3.合同变更和档案管理4.合同违约索赔管理项目合同管理…...

测试开发之Django实战示例 第十三章 上线
在上一章,为其他程序与我们的Web应用交互创建了RESTful API。本章将学习如何创建生产环境让我们的网站正式上线,主要内容有:配置生产环境创建自定义中间件实现自定义管理命令1创建生产环境现在该将Django项目正式部署到生产环境中了。我们将按…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
scikit-learn机器学习
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...