【Rust中的智能指针】
Rust中的智能指针
- 什么是智能指针?
- 什么是Rust中的智能指针?
- Rust中的智能指针Box
- Box的使用场景
- Rust中的智能指针Rc与Arc
- rust中的RefCell
- refcell的缺点:
- rust中的weak
- 先来看看C++中的weak_ptr定义
- 代码示例:
- Deref和Drop
- 总结
什么是智能指针?
传统的指针,如C++中的裸指针,需要开发者自己申请和释放,如果开发者在使用过程中疏漏了回收,将会造成内存泄漏,在部署
实施时也会有oom的风险,智能指针即是为了解决这类问题而出现的,老生常谈的shared_ptr,unique_ptr,weak_ptr等,都是通过设计使得代码自动管理回收堆上的内存,提高代码的健壮性和方便性。
什么是Rust中的智能指针?
Rust由于其严格的安全性和所有权机制,除unsafe写法外,所有的堆内存都是通过语言特性管理的。其目的和其他语言一致都是为了健壮性和方便使用,与C++的智能指针使用的机制并无二致,都是使用了RAII(即资源获取即初始化),常见的rust智能指针有Box,Rc,Arc,Weak等。(个人理解:因为rust中的智能指针常与引用符号&结合使用,与其叫做智能指针,不如叫智能引用。)
Rust中的智能指针Box
首先看一下C++中的unique_ptr:
1.unique_ptr所指向(引用)的资源只能被unique_ptr所独占,不能被Copy,只能被转移。
2.自动析构不计数(结合一中的定义,独占型指针也没有任何计数的必要)
以上是unique_ptr的特点,这也是Rust中Box的主要特点:
只能转移所有权,不能Copy,同时只能有一个有效的Box。
Box的使用场景
由于Box的独占特点,其使用一般可以用在:
- 避免深拷贝一些多字节的数据
- 此文中提到的特征对象作为返回值使用,个人理解这是Box的最有用且最常用之处。
- 作为容器中得item如:
vec![Box<dyn Noise>] //比较适合在实践一些设计模式时使用
代码示例:
fn returns_noise(isdog: bool) -> Box<dyn Noise> {if isdog {Box::new(Dog {voice: String::from("wangwang",),})} else {Box::new(Cat {voice: String::from("miaomiao",),})}
}
Rust中的智能指针Rc与Arc
Rc: 全称 Reference Count,即引用计数。
Arc: 全称Atomic Reference Count,即原子性引用计数。
由定义可知,Arc对比与Rc的一大优点就是原子性,既线程安全。而实现了线程安全势必要损失了一些性能,所以Rc比Arc性能要更好些,这两个智能指针都是只读的 。
Rc与C++中的Shared_ptr机制类似,都是通过引用计数和RAII最终实现对于堆内存的自动控制,两者都是线程不安全的,最大的区别便是Rc只读。
代码示例
{ let rc1 = Rc::new(String::from("hello world"));let rc2 = Rc::clone(&rc1);let rc3 = Rc::clone(&rc1);
}{ let mystr = String::from("hello world");let bx2 = Box::new(&mystr);let bx3 = Box::new(&mystr);//got error
}
以上是Rc与Box间的对比,由于所有权的转移bx3在二次借用时便会出错,而rc拥有计数规则,上述代码将通过编译。
这里细心的同学会留意到clone,这里只是浅拷贝。
原则上,栈上数据基本都可以直接复制,而堆上内存申请性能相对较慢,堆上内存非必要情况下不做深拷贝,同理,如果你作为一个语言开发者,非必要情况下也不会默认将堆上内存直接深拷贝。
Arc是Rc的线程安全版本,用法函数基本一致,不做代码示例,有需要可用自行查阅。
rust中的RefCell
在之前我们提到过Rc与C++中的shared_ptr很接近,但是是只读的,如何做到内部可变 —> 结合RefCell。
内部可变:在不改变外部套壳的情况下,可更改内部数值。
let s = Rc::new(RefCell::new("hello ".to_string()));let s1 = s.clone();let s2 = s.clone();s2.borrom_mut().push_str("world");println!("{:?}",s);println!("{:?}",s1);println!("{:?}",s2);
均打印出 hello world
refcell的缺点:
代码使用了refcell后,rust被遵循的借用三大规则被移动到运行时,强制panic(也算比较安全,至少比unsafe从字面上的来看更舒服些)
rust中的weak
先来看看C++中的weak_ptr定义
std::weak_ptr is a smart pointer that holds a non-owning (“weak”) reference to an object that is managed by std::shared_ptr. It must be converted to std::shared_ptr in order to access the referenced object.
std::weak_ptr models temporary ownership: when an object needs to be accessed only if it exists, and it may be deleted at any time by someone else, std::weak_ptr is used to track the object, and it is converted to std::shared_ptr to acquire temporary ownership. If the original std::shared_ptr is destroyed at this time, the object’s lifetime is extended until the temporary std::shared_ptr is destroyed as well.
Another use for std::weak_ptr is to break reference cycles formed by objects managed by std::shared_ptr. If such cycle is orphaned (i.e., there are no outside shared pointers into the cycle), the shared_ptr reference counts cannot reach zero and the memory is leaked. To prevent this, one of the pointers in the cycle can be made weak.
总之,weak_ptr很弱,只记录状态信息,不保证一定存在,同时(主要)为了解决shared_ptr造成的循环引用,通常也不会单独出现,必须要转换成shared_ptr.
对比rust中的weak也是几乎一样的设计理由和使用条件,不保证引用一定存在,所以它返回Option< Rc < T > >,代码写法即upgrade升级到Rc,或将Rc降级到weak。
代码示例:
use std::rc::{Rc, Weak};
use std::cell::RefCell;
#[derive(Debug)]
struct Node {value: i32,parent: RefCell<Weak<Node>>,children: RefCell<Vec<Rc<Node>>>,
}fn main() {let _leaf = Rc::new(Node {value: 3,parent: RefCell::new(Weak::new()),children: RefCell::new(vec![]),});
}
Deref和Drop
- Deref: 将引用中的实际值解出并使用,是Rust中最常见的隐式转换,如将String类型传入 &str入参时等等
- Drop: 释放资源,类似于析构函数,同样的,有默认实现,也有主动重写。
- Deref 是特征,一般开发者仅会为自定义的智能指针实现解引用特征。
- 解引用可递推,所以在隐式转换时常常有多层的解引用。
总结
本章结合题目非常适合链表练习。
如有勘误,敬请指出。
相关文章:
【Rust中的智能指针】
Rust中的智能指针 什么是智能指针?什么是Rust中的智能指针?Rust中的智能指针BoxBox的使用场景 Rust中的智能指针Rc与Arcrust中的RefCellrefcell的缺点:rust中的weak先来看看C中的weak_ptr定义代码示例: Deref和Drop 总结 什么是智…...
基于深度学习的社交网络中的社区检测
在社交网络分析中,社区检测是一项核心任务,旨在将网络中的节点(用户)划分为具有高内部连接密度且相对独立的子群。基于深度学习的社区检测方法,通过捕获复杂的网络结构信息和节点特征,在传统方法基础上实现…...

【Python基础】
一、编程语言介绍 1、分类 机器语言 (直接用 0 1代码编写)汇编语言 (英文单词替代二进制指令)高级语言 2、总结 1、执行效率:机器语言>汇编语言>高级语言(编译型>解释型) 2、开发效率&…...

【玉米叶部病害识别】Python+深度学习+人工智能+图像识别+CNN卷积神经网络算法+TensorFlow
一、介绍 玉米病害识别系统,本系统使用Python作为主要开发语言,通过收集了8种常见的玉米叶部病害图片数据集(‘矮花叶病’, ‘健康’, ‘灰斑病一般’, ‘灰斑病严重’, ‘锈病一般’, ‘锈病严重’, ‘叶斑病一般’, ‘叶斑病严重’&#x…...

【设计模式】如何用C++实现依赖倒置
【设计模式】如何用C实现依赖倒置 一、什么是依赖倒置? 依赖倒置原则(Dependency Inversion Principle,DIP)是SOLID面向对象设计原则中的一项。它的核心思想是: 高层模块不应该依赖于低层模块,两者都应该…...

使用onnxruntime-web 运行yolov8-nano推理
ONNX(Open Neural Network Exchange)模型具有以下两个特点促成了我们可以使用onnxruntime-web 直接在web端上运行推理模型,为了让这个推理更直观,我选择了试验下yolov8 识别预览图片: 1. 跨平台兼容性 ONNX 是一种开…...
Gin框架html/vue前端使用hls.js播放/点播m3u8(hls)格式视频
说明 在web应用开发时遇到在线播放m3u8格式视频,由于m3u8是多分片视频,原生video标签无法直接播放,所以需要js对m3u8处理才能播放,网上有很多插件,这里我选择最近简单方法hls.js播放,引入一个js文件即可。…...

HarmonyOS 私仓搭建
1. HarmonyOS 私仓搭建 私仓搭建文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-ohpm-repo-quickstart-V5 发布共享包[https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-har-publish-0000001597973129-V5]…...

Mybatis学习笔记(二)
八、多表联合查询 (一) 多表联合查询概述 在开发过程中单表查询不能满足项目需求分析功能,对于复杂业务来讲,关联的表有几张,甚至几十张并且表与表之间的关系相当复杂。为了能够实业复杂功能业务,就必须进行多表查询,…...

Google“Big Sleep“人工智能项目发现真实软件漏洞
据Google研究人员称,该公司的一个人工智能项目足够聪明,能够自行发现现实世界中的软件漏洞;Google的人工智能项目最近在开源数据库引擎 SQLite 中发现了一个之前未知的可利用漏洞。 该公司随后在正式软件发布之前报告了这一漏洞,这…...
npm入门教程5:package.json
一、package.json 文件的作用 依赖管理:列出项目所依赖的包(库)及其版本,便于其他开发者或自动化工具快速安装和更新这些依赖。元数据描述:提供项目的描述、作者、许可证等元信息,有助于项目的管理和维护。…...
docker-高级(待补图)
文章目录 数据卷(Volume)介绍查看方法删除方法绑定方法匿名绑定具名绑定Bind Mount 数据卷管理 网络bridge(桥接模式 默认)HOST(主机模式)Nonecontainer(指定一个容器进行关联网络共享)自定义(推荐)docker network 命令创建网络docker network create 实例展示-自定义实例展示-…...

Qt 文件目录操作
Qt 文件目录操作 QDir 类提供访问系统目录结构 QDir 类提供对目录结构及其内容的访问。QDir 用于操作路径名、访问有关路径和文件的信息以及操作底层文件系统。它还可以用于访问 Qt 的资源系统。 Qt 使用“/”作为通用目录分隔符,与“/”在 URL 中用作路径分隔符…...

Pandas 数据清洗
1.数据清洗定义 数据清洗是对一些没有用的数据进行处理的过程。很多数据集存在数据缺失、数据格式错误、错误数据或重复数据的情况,如果要使数据分析更加准确,就需要对这些没有用的数据进行处理。 2.清洗空值 DataFrame.dropna(axis0, howany, threshN…...

IO学习笔记
当前需求,希望进行游戏可以保存游戏进度,可以将游戏的进度保存到一个文本文件,每一次打完游戏更新文本内容,下一次打游戏读取游戏进度,这里就涉及到两个知识IO流和File的知识。 File类 概述 java.io.File 类是文件…...

汇编练习-1
1、要求 练习要求引自《汇编语言-第4版》实验10.3(P209页) -编程,将data段中的数据,以10进制的形式显示出来 data segment dw 123,12666,1,8,3,38 data ends 2、实现代码(可惜没找到csdn对8086汇编显示方式) assume cs:codedata segmentdw 16 dup(0) ;除…...

初识二叉树( 二)
初识二叉树 二 实现链式结构二叉树前中后序遍历遍历规则代码实现 结点个数以及高度等层序遍历判断是否为完全二叉树 实现链式结构二叉树 ⽤链表来表示⼀棵二叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成,数据域和左右指针…...

AcWing1077-cnblog
问题背景 给定一个树形结构的图,每个节点代表一个地点,每个节点有一个守卫的代价。我们希望以最低的代价在树的节点上放置守卫,使得整棵树的所有节点都被监控。可以通过三种方式覆盖一个节点: 由父节点监控。由子节点监控。自己…...
五、SpringBoot3实战(1)
一、SpringBoot3介绍 1.1 SpringBoot3简介 SpringBoot版本:3.0.5 https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started.html#getting-started.introducing-spring-boot 到目前为止,你已经学习了多种配置Spring程序的方式…...

练习LabVIEW第三十三题
学习目标: 刚学了LabVIEW,在网上找了些题,练习一下LabVIEW,有不对不好不足的地方欢迎指正! 第三十三题: 用labview编写一个判断素数的程序 开始编写: LabVIEW判断素数,首先要搞…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...
字符串哈希+KMP
P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...