c++--智能指针(RAII)

智能指针可以帮助我们管理动态空间,即自动释放动态空间。

---------------------------------------------------------------------------------------------------------------------------------

简单原理

事实上,智能指针的原理就是将指向动态空间的指针托管给一个自定义对象(把这个指针作为成员变量),然后在析构函数中将动态空间释放。这样就实现了动态空间的生命周期与对象的生命周期相同。如果要使用这个指针,我们只需要在类里面重载*,->等运算符或者写成员函数即可。

---------------------------------------------------------------------------------------------------------------------------------

智能指针的历史及主要困难

智能指针在c++98中就已经被引入,即现在c++库中的auto_ptr类模版。但是它在拷贝时有一个缺陷:

为什么报错呢?本来我们想要x和y共同管理一块动态空间,但是因为 auto_ptr 中的拷贝实际上是管理权转移,也就是说,当把x拷贝给y的时候,x就没有了该动态空间管理权(存放动态空间指针的成员变量被置为空了),所以x->year++实际上是对空指针操作,所以会报错。

为什么非要实现拷贝呢?不让它拷贝行吗?不行,我们总有一些情况是需要拷贝的,比如说:

push_back中就会拷贝(赋值拷贝),但是拷贝就会产生上述问题。还有传参等情况。

那么库里面为什么不能不把x置为空?这样也不行,因为会导致被管理的指针析构两次而报错。

这就是智能指针的困难

可以看出auto_ptr是不成熟的,但是如果在库里删除它会让一些已存在的使用了它程序无法运行。为了避免像auto_ptr这种尴尬的情况,后续委员会成员先在boost库(c++扩展库)写功能,如果好用的话才纳入c++标准库。boos库中就有新的好用的智能指针shared_ptr,unique_str(简单粗暴禁止拷贝,适用面不广)等,他们在c++11中被纳入标准库。

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中的实现的

---------------------------------------------------------------------------------------------------------------------------------

shared_ptr

这个是比较好用的一种智能指针。它通过引用计数的方式解决拷贝问题。

原理:对于管理同一份资源的智能指针,不在采用管理权转移的方式,让他们都有管理权,这样会导致析构两次,所以我们再让这些智能指针管理同一个计数器,每多一个智能指针管理这个资源,计数器加1,每析构一个智能指针,计数器减1。如果计数器成为0,说明这个智能指针是唯一的管理者,此时如果它析构,我们就把资源也释放了。

这种方式防止了析构多次以及同一份资源不能被多个智能指针管理的缺陷,俗称“最后一个离开房间的人关灯”

---------------------------------------------------------------------------------------------------------------------------------

接下来简单实现一下share_ptr

1.

这是类模版的头,T用来接收任意类型的资源

2.

_ptr指向存放动态资源的指针。

_count是指向计数器。管理同一个资源的智能指针中,这个指针指向的计数器相同。这个计数器是动态开辟的,在资源释放的时候将他也释放。我们给它缺省值为1。

_delete是删除器。智能指针指向的资源不光是一个动态开辟的变量(用delete释放),也有可能是FILE类型(用fclose释放),还有可能是动态数组类型,用delete[]释放,总之释放资源的方式是不同的,但我们写的模版要使用所有类型,所以我们在用智能指针管理资源的时候需要传入一个可调用对象(删除器),通过传入不同的删除器,实现资源的正确释放。至于为什么用包装器(function<void(T*)>),我们稍后再说。

3.

这是类模版的构造函数。

第一个函数是一个函数模版D是函数模版参数,由你传入的对象类型决定,T是类模版参数,由类决定。我们知道删除器是要释放资源,而释放资源是在析构函数内部,也就是说,我们要在析构函数内部使用D类型的对象。在一个函数传入,在另一个函数使用,如何做呢?他两共有的可以访问的是成员变量,所以我们可以用成员变量来接收这一对象,然后另一个函数就可以使用了。

那么问题又来了,这个成员变量应该是什么类型呢?是D,但问题是,D是函数模版参数,类模版没有这个模版参数,它不认识D,这时候就需要包装器了,它可以包装任何可调用对象,且只需要返回值和参数类型,参数类型就是指向资源的指针T*,返回值类型就是void

function<void(T*)> _delete = [](T* x)->void {delete x; };

而[](T* x)->void {delete x; }是一个lambda表达式,它作为删除器的缺省值,使得不传删除器的时候也可以有默认删除器使用。

至于为什么不直接把删除器设计成类模版参数,这是因为我们要模拟库的实现,哪种都可以的。

第二个函数是普通的构造函数

4.

这是析构函数。智能指针析构时,要先让count--,然后判断是否需要释放资源,也就是count是否为0(即这是最后一个管理这个资源的智能指针)。

而我把逻辑封装在release函数里。

5.

这是shared_ptr的关键,拷贝构造和赋值拷贝。

一但拷贝构造或者拷贝赋值,说明多了一个智能指针管理相同的资源,所以_count++。

对于拷贝复制,先得把该智能指针原来管理的资源清理(复用 release),然后接收新的资源。

6.

这是关于被管理资源的使用函数。const需要加上,以便const对象和非const对象都能调用这些函数,可以自己写去体会一下为什么要加。

---------------------------------------------------------------------------------------------------------------------------------

shared_ptr的循环引用

这是一个典型例子,下面是分析

这是shared_ptr的缺陷!

解决方法:

仿造库里面的weak_ptr,我们设计出自己的简化的weak_ptr(库里面要复杂许多倍)。

把节点改成这样:

用weak_ptr代替节点中的shared_ptr,shared_ptr可以赋值给weak_ptr(通过weak_ptr的赋值拷贝),weak_ptr管理一个资源不会增加计数器。这样,x->_next = y,y->_prev = x 后,count1,count2还是1而不是2,此时在走一遍上述过程,你会发现循环引用已经破除了。

---------------------------------------------------------------------------------------------------------------------------------

对了,weak_ptr可以通过lock函数恢复到shared_ptr,这里只是简单介绍智能指针,说的不全面,见谅

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/415635.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅谈人工智能之Windows:基于ollama进行本地化大模型部署

浅谈人工智能之Windows&#xff1a;基于ollama进行本地化大模型部署 引言 随着人工智能技术的飞速发展&#xff0c;大型语言模型&#xff08;LLMs&#xff09;已经成为推动自然语言处理领域进步的关键力量。然而&#xff0c;传统的云部署方式可能带来数据隐私、成本以及访问速…

【滑动窗口】将 x 减到 0 的最小操作数

将 x 减到 0 的最小操作数 将 x 减到 0 的最小操作数题目思路讲解代码书写 将 x 减到 0 的最小操作数 题目 题目链接: 将 x 减到 0 的最小操作数 思路讲解 按照题目的思路去做这一题是非常恶心的, 因此我们采用正难则反思路. 将问题转换为: 求中间某一个最长的数组长度, 使…

hyperf json-rpc

安装 安装docker hyperf 安装 hyperf-rpc-server-v8 &#xff08;服务端&#xff09; docker run --name hyperf-rpc-server-v8 \ -v /www/docker/hyperf-rpc-server:/data/project \ -w /data/project \ -p 9508:9501 -it \ --privileged -u root \ --entrypoint /bin/sh \…

Unity学习路线

目录 一、Unity官方推荐路线二、AI总结的学习路线1、Unity学习路线图&#xff08;文言一心&#xff09;一、基础入门&#xff08;初级&#xff09;二、进阶提升&#xff08;中级&#xff09;三、高级深入&#xff08;高级&#xff09;四、专家级探索 注意事项 2、Unity学习路线…

【2024 CCF编程能力等级认证(GESP)C++ 】 计算机基础知识

目录 1. 引言2. 计算机系统结构2.1 中央处理器&#xff08;CPU - Central Processing Unit&#xff09;2.1.1 运算器 2.1.2 控制器2.1.3 性能指标2.2 存储器2.3 输入设备2.4 输出设备 3. 计算机系统层次结构4. 操作系统4.1 操作系统分类4.2 操作系统常见操作4.2.1 基本开关机操…

Mqtt消费端实现的几种方式

此处测试的mqtt的Broker是使用的EMQX 5.7.1&#xff0c;可移步至https://blog.csdn.net/tiantang_1986/article/details/140443513查看详细介绍 一、方式1 添加必要的依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spr…

直播相关概念

文章目录 1、腾讯云直播2、直播&#xff1a;视频直播3、常用的直播组合&#xff1a;4、推流&#xff1a;主播通过推流地址进行视频的推送5、拉流&#xff1a;观众通过拉流地址进行视频的播放6、准备工作6.1、进入腾讯云直播 1、腾讯云直播 直播即时聊天&#xff1a;打赏 文字 …

Linux运维--iptables防火墙命令以及端口号等详解(全)

Linux之iptable防火墙命令以及端口号等详解&#xff08;全&#xff09; 在Linux系统中&#xff0c;你可以使用firewalld和iptables来管理和设置防火墙规则。Firewalld是一个动态管理防火墙的工具&#xff0c;而iptables是一个更底层的工具&#xff0c;可以直接配置Linux内核的…

【重学 MySQL】一、数据库概述

【重学 MySQL】一、数据库概述 为什么要使用数据库数据库与数据库管理系统数据库&#xff08;Database&#xff09;数据库管理系统&#xff08;DBMS&#xff09;数据库与数据库管理系统的关系数据库是数据存储的容器数据库管理系统是数据库的管理者相互依存的关系数据库系统的组…

【网络安全】服务基础第一阶段——第六节:Windows系统管理基础---- DNS部署与安全

计算机智能识别并用IP地址定位&#xff0c;例如我们想要访问一个网页&#xff0c;其实是只能使用这个网页的IP地址&#xff0c;即四位的0&#xff5e;255来访问&#xff0c;但这一串数字难以记忆&#xff0c;于是就有了DNS&#xff0c;将难以记忆的数字转化为容易记忆的域名&am…

Elasticsearch 介绍

1、课程介绍 1.1 ES 8.x 演化进程 版本号发布日期多少个次要版本迭代历时8.02022年2月11日&#xff1f;至今7.02019年4月11日17个次要版本34个月6.02017年11月15日8个次要版本17个月5.02016年10月27日6个次要版本13个月 2、Elasticsearch 是什么 2.1 概念 2.1.1 标准定义 …

文件上传的学习

文件上传漏洞 文件上传漏洞是指由于程序员在对用户文件上传部分的控制不足或者处理缺陷&#xff0c;而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。这里上传的文件可以是木马&#xff0c;病毒&#xff0c;恶意脚本或者WebShell等。“文件上传”本身没有…

计算机二级 C程序设计(2020B场)全解

A选项&#xff1a;C语言中&#xff0c;一共有3种结构。分别是顺序结构、选择结构&#xff08;else-if语句&#xff09;、循环结构&#xff08;for、while语句&#xff09;。因此&#xff0c;C语言具有结构化特征。 B选项&#xff1a;不仅能解决简单问题&#xff0c;3种基本结构…

WPF MVVM如何在ViewModel直接操作控件对象

早些年在WPF中使用COM组件时&#xff0c;需要在ViewModel中操作COM组件中的控件对象&#xff0c;但是这个控件对象又不支持绑定&#xff0c; 后面的解决办法是在窗口加载时&#xff0c;将控件对象以参数传递到Loaded事件的处理命令中&#xff0c;然后将这个对象记录下来&#…

Ubuntu 18.04升级gclibc为2.28版本

一、查看系统支持的 GLIBC 版本号 ​strings /lib/x86_64-linux-gnu/libc.so.6 | grep GLIBC_出现以下&#xff0c;说明到2.27版本&#xff0c;没有2.28版本&#xff0c;所以我们需要手动安装 GLIBC_2.2.5 GLIBC_2.2.6 GLIBC_2.3 GLIBC_2.3.2 GLIBC_2.3.3 GLIBC_2.3.4 GLIBC_…

Docker入门笔记

Docker 文章目录 Docker1. 下载 &#xff08;centos&#xff09;2. 部署 MySQL3. 常用命令4. 数据卷5. 自定义镜像6. Java 项目部署 1. 下载 &#xff08;centos&#xff09; 卸载旧版 yum remove docker \docker-client \docker-client-latest \docker-common \docker-lates…

84、 k8s的pod基础+https-harbor

一、pod基础&#xff1a; pod进阶&#xff1a;探针&#xff08;面试必问—扩缩容&#xff0c;挂载&#xff09; 1.1、pod的定义 pod是k8s里面的最小单位&#xff0c;pod也是最小运行容器的资源对象。 容器时基于pod在k8s集群当中工作。 在k8s集群当中&#xff0c;一个pod就…

第二阶段:机器学习经典算法-02决策树与随机森林-1.决策树概述

该视频主要讲述了决策树与随机森林算法的基本概念和构造过程。决策树是一个树形结构&#xff0c;用于进行一系列的决策&#xff0c;可以用于分类和回归问题。随机森林算法是基于决策树的集成学习算法&#xff0c;通过构建多棵决策树并结合它们的预测结果来提高分类准确率。视频…

asp.net core web api项目添加自定义中间件

前言 在asp.net core web api项目中&#xff0c;默认提供了很多的中间件&#xff0c;比如访问静态文件中间件UseStaticFiles&#xff0c;跨域配置中间件UseCors&#xff0c;路由中间件UseRouting,身份验证中间件UseAuthentication。 那么如何添加一些自定义的中间件呢。 需求…

java SpringBoot 使用ijpay对接微信支付-商家转账到零钱

使用的maven版本&#xff1a;2.9.11 由于ijpay中提供的实体类没有设置回调参数的属性&#xff0c; 这里是自定义一个实体类:InitiateBatchTransferRequest代码如下&#xff1a; package com.foo.web.controller.pay.wxpay;import com.ijpay.wxpay.model.v3.TransferDetailInput…