【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 Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
基于Java+VUE+MariaDB实现(Web)仿小米商城
仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
