右值引用: 移动语义

右值引用:移动语义 左值与右值 左值有标识 标识:你有某个值,并有某个值的内存地址,可以安全的使用它 左值(lvalue)可以出现在赋值的左侧(当我们使用他的名称时),也可以出现在赋值的右侧(当我们使用他的值时)。因此当我们称某个值为左值时,他未必出现在等号左侧,而是认为他有标识。 这里的左值严格意义上称为泛左值,包括左值和将亡值两种。 右值可移动,左值不能 有些值并非泛左值,换句话说你无法获得其内存地址并使用。这类值的优点是可以移动他而不是复制它。(通常情况下移动要比赋值开销小很多)。移动一个值意味着他不会在原来的位置,当你称一个值可以移动时,我们认为是右值。 左值是不可移动的,因为这破坏了左值的概念:通过内存地址使用 右值引用的对象,是临时的,即将被销毁。 纯右值 纯右值没有标识,因此我们无法使用他的内存地址,但他是可以移动的(因为是右值)。 值类别汇总 泛左值(glvalue):有标识 左值:有标识但不能移动 将亡值:有标识,但也可以移动,是之前的某个左值变成了右值引用。 纯右值:没有标识,可以移动。 右值:可移动 左值持久,右值短暂 左值引用与右值引用 重新观察T& 重新观察T&和const T&,他们现在实际上是对左值的引用。左值引用可以绑定到左值,但不可以绑定到右值。 左值引用时,我们将一个对象的内存空间绑定到另一个变量上,因此我们使用的是一个对象在内存中的位置,这是一个左值。 右值引用 通过T&&可以标识一个类型T的右值引用,右值引用引用了一个可移动值,其内容在使用后无需保留。右值引用绑定到右值而非左值(右值引用假定内容无需保留而进行移动的值)。 右值引用意味着:1.右值是临时的,即将被销毁。 2.右值引用的对象不会在其他地方使用。 这两个特性意味着:接受和使用右值引用的代码,可以自由地接管所引用的对象的资源,而无需担心对其他代码逻辑造成数据破坏。 右值引用是左值还是右值 对于左值引用,当我们想要使用他的值时,他是右值,当我们想要使用他的地址(内存空间)时,他是左值。对于右值引用也一样,当我们进行右值引用时,右值的变量已经被右值引用接管了,这个时候的变量可以通过右值引用保存下来,因此可以成为左值。而我们也可以直接使用右值引用的值,这个时候右值引用会作为右值。 移动语义 右值引用支持“移动语义”,利用移动语义,你可以让一个对象转移到另一个对象而非使用拷贝构造,他也可以使用临时对象转移资源。 右值中的数据可以被安全移走使得右值可以用来表达移动语义。 考虑vector对象的实例,当vector容量满时,我们会开辟一块新的空间并将内容拷贝构造到新空间,销毁之前的空间。但拥有了移动语义后,我们可以实现移动而非拷贝,这可以避免成本高昂的内存分配和复制操作。

October 7, 2022 · yunlang

数据库系统(一)

数据库系统 数据库 什么是数据库? 将信息以某种形式存储在一起。 数据库的重要位置 系统软件之一,为多种应用软件提供基础。 注意数据库(Database)与数据库管理系统(Database management system,DBMS)的区别。 传统数据整理 传统数据整理的方式:一种方式为 CSV 的表格式存储。 缺点:安全性,效率性,使用时的复杂度等。 如无法保证在数字栏插入的一定是数字。检索需要遍历,出现问题容易直接崩溃等。 早期的DBMS DBMS:软件层面上对数据模型进行定义,提供了增删改查等功能。 早期的数据模型:逻辑与物理紧密结合,必须对特定的数据库场景安排对应的处理应用。 根本原因为物理存储上直接采用应用对数据格式,位置等进行规定,因此切换场景等都需要重新进行设计。 关系模型 基于关系定义了一种数据模型的抽象。 利用一种简单的数据结构(关系)进行数据库存储 用户操作基于高级语言,DBMS 负责具体执行策略 物理存储由 DBMS 负责实现。 关系模型是将无序的各种数据通过关系串联起来,而对这些数据的操作和物理存储的实现都交给了 DBMS,因此使用者可以相对透明的完成对数据的处理。 关系模型也定义了三个概念: 数据结构 数据操作 数据约束 关系模型利用了数学上的关系定义 主键与外键 主键:每个关系中唯一的键,作为该关系的关键字。(如省略,一般会自动生成) 外键:提供关系与关系间的纽带。 DML Data Manipulation Languages,数据操作语言,用来操作数据库表中的记录。 中文可以理解成增删改查四种操作。 常见的两种分类: Procedural: 指定了做什么,和如何做 Non-Procedural(Declaratice): 仅仅指定了做什么 关系代数 关系代数是对关系模型中各种运算操作的集合(前面说了关系模型其实是一种数学的关系定义)。 注意和数学上的关系运算并不完全相同。 “选择”、“投影”、笛卡尔积(也叫做“叉积”或“交叉连接”)、并集、差集、“重命名”、“自然连接”。 利用关系代数我们可以解释两种 DML 的不同之处: Procedural:σb id=102(R ▷◁ S),既解释了做什么,也解释了如何做 Non-Procedural:(retrieve the joined tuples from R and S where bid equals 102,只说明了做什么,没有说明如何做,指定关系代数顺序) 第二种交给了 DBMS 来完成。 ...

September 2, 2022 · yunlang

利用分支完成 github pages 博客内容存放和页面部署

前言 我利用github pages作为平台搭建我的博客,我开始选择将博客内容和部署分成两个仓库存放,但这显然造成了复杂性的提升。在阅读 mdbook 的官方文档时,我发现他部署 book 的一个方式是利用一个新的分支进行部署,这样可以将内容和页面放在不同的分支上共同保存,同时有好的规整感。 原理 在 github 仓库的 Settings/Pages 下可以选择利用哪一个分支进行部署。 利用 github worktree 可以将当前分支绑定到一个新建的 worktree 目录上,并通过新的目录进行分支操作。 使用 新建分支 deploy 和 /tmp/blog 目录,利用github worktree 将目录 deploy 分支绑定到目录下。 将生成的页面文件(我这里在public文件夹中),拷贝到 /tmp/blog 目录下 在 /tmp/blog 下利用 git 操作,添加并提交到远程 deploy 分支中。 设置 github pages,用 deploy 分支作为 github pages 部署分支。 现在你可以将内容提交到 main 分支,而将部署提交到 deploy分支。 为什么使用临时目录 使用临时目录的样例来自 mdbook 的文档。因此我只是当一个黑盒来使用。我的想法是为了不破坏其他数据,不过有了解的朋友也欢迎来给我答疑解惑。 我的 Makefile 文件 .PHONY: deploy .PHONY: clean .PHONY: build .PHONY: commit clean: rm -rf public deploy: public @echo "====> deploying to github" -mkdir /tmp/blog git worktree prune -git worktree add /tmp/blog deploy rm -rf /tmp/blog/* cp -rp public/* /tmp/blog/ cd /tmp/blog && \ git add -A && \ git commit -m "deployed on $(shell date) by ${USER}" && \ git push origin deploy cd - build: hugo commit: git add Makefile config.yml assets static content layouts archetypes git commit -m "commit on $(shell date) by ${USER}" && \ git push origin main

September 2, 2022 · yunlang

数据处理练习

目标 对这个 网页中的数据集进行数据处理,选择一列 找出最大值和最小值, 选择其中两列求出差值并求和. 步骤 对于html, 可以使用wget或curl读入. 处理html内容可以采用pup工具来实现. 下载网页到本地 wget https://stats.wikimedia.org/EN/TablesWikipediaZZ.htm -O pra.html 对网站元素进行查看 最好的方法是使用浏览器的审查元素方式进行查看, 能够较快的找到自己所需的内容. 可以看到我们所需的数据表格在table中,id为table1.更近一步观察可以看到位于tbody中.可以通过pup过滤并 输出内容. 数据处理 通过pup获取html中第一个表格的数据 cat pra.html | pup 'table#table1 tbody td next{}' 此时内容如图 去除头部和尾部部分行 对于表格文件,我只关心表格中间的数据,而忽略表头和表尾,这里采用head和tail进行过滤. 删除尾部30行,删除头部208(209-1)行. head -n -30 tail -n +209 将列变为行,以空格分割 相对于一列,我更喜欢处理以整行数据,这样就可以利用awk的$获取分割. 通过tr命令进行替换 tr '\n' ' ' awk awk是一种善于处理文本的编程语言,他太强大了,以至于我们可以用awk完成其余的所有操作. awk '{sum = 0;max = 0; min = 65536;for(i = 2;i < 4302; i+=20) {if(max < $i) max = $i; if(min > $i) \ min = $i; if($i > $(i+1)) sum += $i - $(i+1); if($i <= $(i+1)) sum += $(i+1) - $i;}print max; print \ min; print sum } 正如我们所说,awk是一种编程语言,代码块中,$0 表示整行的内容,$1 到 $n 为一行中的 n 个区域,区域的 分割基于 awk 的域分隔符(默认是空格,可以通过-F来修改)。 ...

May 14, 2022 · yunlang

对大一应该学些什么的一点思考

前言 最近一直在做一生一芯,跟着做了些PA的项目,感觉自己之前很多所学都有了很多欠缺,也越发发现学校在培养计 划上的自己认为的一些不合理地方,在此记录下:自己如果回到大一,可能会如何开始学习(顺带考虑一下培养计划)。 大一上 应该在大一上学到一门导论课,去知道自己大学四年应该学什么,可以学什么,同时可以将这些知识进行一个简单的串联, 未必要将每一个知识点学的很深,但希望可以覆盖到每一个知识点。 程序设计基础肯定要有,但课设(挺想把C语言课设搬到大一上的,这里一并说了)希望可以有一个培养为上,内容次之的 过程。 现在的课设很多开始已经是报告要卷,内容要卷的状态了。什么数据库,前端,GUI,一些“卷王”做出了很多远超于 课设本身内容的事情。 希望课设是将课上所学实践起来。而不是在各种内容之外的地方去竞争。也希望未来的学弟学妹都能够真正自己思考,动手 写出课设,而不是在网上copy代码。 可以让学生多学一些工具,比如利用git进行团队协作(老实说这个我现在都还没做好),通过make工具链编译。未必要成为 课设加分项,但也可以让学生开始接触一些试试(我现在就在被makefile折磨)。 这里点赞一下我们的实验课老师,他实验课的开始就让我们体会了一些git的用法,据说现在学弟学妹还可以在CG平台实验了。 大一下 学会工具使用!学会工具使用!学会工具使用! 一定需要一门课来教一些工具的使用了,命令行,shell,版本控制,文本编辑…。狂吹The missing semester of your CS education 。 如果说大一上已经开始接触git了,你可能感受到(或没有)他的便利,如果没有,尝试继续在日常使用。 如果你没有开始,用qq,U盘传文件的方式已经让你感到麻烦,开始git吧,找寻一种更高效(开始可能不)的方法。 学会使用这些工具未必能让你立刻觉得你付出的时间会有回报,但他们一定会穿插在你学习计算机的每一个时刻。 对于C++,老师上课第一件要说的就是:学的是面向对象程序设计,只是用C++来教学,因此将更多实时间放在面向对象 上应该是个好主意。 装一台虚拟机,装上linux(颇有私货),但从无到有掌握linux确实能提高很多你的能力(包括查阅文档)。 建议 老师的PPT很老,对于教学来讲足够了,但对于计算机前沿来讲显得过于陈旧。可以多上网冲浪看一看,现代计算机发展到了哪一个阶段。 多实践,多敲键盘,学会计算机的最好办法。 查阅手册,查看代码,搜索网页。解决问题的最好办法 结语 祝你早日成为计算机科学家

April 15, 2022 · yunlang

Dijkstra算法-三种实现与复杂度分析

介绍 Dijkstra算法解决的是带权重的有向图上单源最短路径问题,该算法要求所有边的权重都为非负值。 算法主要通过维护结点集合S。通过从结点集V-S中选择最短路径最小的结点u,将其加入进S中,并对所有从u发出可到达V-S集合中结点的边进行松弛操作。 对邻接表进行操作 松弛操作:对于一条从 顶点u指向 顶点v的边 u–>v来说,如果满足 d[u]+w(u,v)<d[v],就更新 d[v],使得 d[v]=d[u]+w(u,v);这就是对 边uv的一次松弛操作; 其中,w(u,v)表示边的权重,d(u)表示顶点u到达源s的最短距离(目前已知) 因此我们可以将算法理解为三个操作: 找到V-S集合中距离S集合最小结点 将结点加入S集合中 对V-S中剩余结点进行松弛操作。 算法描述 解释 算法的主要逻辑为while循环。Q始终为Q=V-S。每一次通过EXTRACT-MIN(Q)取出Q中距离最小值u。并将u放入S集合中。之后在for循环中对Q中剩余结点进行松弛操作。 对距离进行更新。 分析 算法通过每次从Q中找出距离最小的一个结点插入到S中,并将Q中剩余的结点距离进行松弛,直到Q中没有结点结束。因为Q中初始结点一共有V个,因此一定会有一次O(V)操作(全部插入)。 注意到我们每次只需要松弛刚插入结点连接到的表,由于采用邻接表操作,我们对每一个边只会松弛一次,因此一共会执行|E|次。 找到最小结点的操作可以有多种方式实现,下面介绍三种。 利用一次遍历实现(常通过维护数组) 我们每一次都通过遍历Q中全部结点找到最小值,这时候需要对一次插入结点都需要执行一个O(V)操作。算法的时间复杂度为 $$ O(V^2 + E) = O(V^2) $$ 利用二叉堆实现 显然,如果我们每一次都要找到最小值,可以通过使用二叉堆实现优先队列来优化寻找最小值的算法。这样我们可以将查找最小值的操作优化到O(lgV) 而对于二叉堆,每一次修改距离并加入到二叉堆都需要一次更新,因此复杂了松弛操作,时间复杂度为 $$ O((V+E)lgV) $$ 即每一次删除Q中一个结点和将结点距离松弛化都需要lgV时间 因此,是否优于第一种需要考虑E的范围,即图是稀疏图还是稠密图 利用斐波那契堆 斐波那契堆的对于找到最小值并进行删除需要的时间与二叉堆一样,都是O(lgV),但对松弛操作,斐波那契堆的摊还代价是O(1),因此可以实现更好的优化,他的时间复杂度为 $$ O(VlgV + E) $$

April 11, 2022 · yunlang

Rust介绍

Rust介绍 官网对rust的介绍为一门赋予每个人构建可靠且高效软件能力的语言。 Rust是一门系统编程语言。简单来说,系统编程语言是一种资源受限的编程,你需要对每个字节和每个CPU时钟周期精打细算,做到高效的完成任务。 常见的系统编程应用场景: 操作系统 各种设备驱动 文件系统 数据库 嵌入式设备 内存管理程序 高级编程语言 虚拟化及软件程序 游戏 等等… 为什么选择Rust 系统编程语言已经有C/CPP了,为什么我还要选择Rust? C语言诞生于1972年,C++诞生于1979年,这至今41+年的时光中一直没有编程语言去挑战他们的地位。 由于时代原因,C和C++是两门过于相信程序员的编程语言,不会去检查程序员出错的代码。 Rust的第一个正式版本发布于2015年,融合了现代编程语言的优秀设计,解决了传统系统编程语言的痛点问题。产生了高性能,可靠性,生产力三个优秀特点。 最值得一提的是可靠性,Rust的设计使得你可以在编译器解决各种错误,而不是运行时。同时他的这种设计也让多核时代的多线程编写变得更加简单。 又有谁没被segmentation fault折磨过呢? 享受编程 一旦你学会了rust,你就会享受到面向编译编译器开发带来的好处(虽然我个人现在还在痛苦当中)。感受前期多用脑子,开发不用脑子的特点了。 官方文档丰富 官方(社区)为Rust提供了许多优良的文档,比如the book,他们本身的优秀使得你可以从官网快速开始学习Rust。 Rust的缺陷之处 学习曲线陡峭 Rust与C-like语言较大的差异使得上手Rust变得困难。为了严格防止未定义行为,Rust又引入了所有权,生命周期等概念。这使得学习Rust的难度进一步提高。 编译时间长 为了保证可靠性,Rust需要在编译时进行大量的检查(编译器教你做事),这使得一个大的项目要花费更多的时间在编译上。更为遗憾的是这个缺点可能需要很久(甚至不可能)改善。 不过现在已经有多线程编译的出现以减少编译时间。 就算你不致力于使用Rust,也可以看一看Rust Rust吸收了许多编程语言的优良设计,并解决了许多过去编程的痛点问题。就算你不使用Rust,去学一学Rust的哲学也可以帮助你成为更好的程序员。

March 18, 2022 · yunlang

Linux小tip------tar与gz

简介 你可能经常看到.tar与.tar.gz文件,但你可能很少思考过他们的用法。下面将介绍他们的区别 tar tar是打包命令,可以把一大堆的文件和目录打包成一个文件,方便文件的备份和文件在网络中的传输。 弄清打包和压缩的概念,打包并不会减小文件的大小。 当我们想要将多个文件压缩成一个压缩包时,我们需要先对这些文件进行打包,然后再用压缩程序进行压缩。 gz(误) gz并不是一个正确的说法,事实上你可以单独使用gzip等压缩程序对文件进行压缩,常见的.tar.gz是直接用tar打包并通过应用程序进行压缩的一种方式。 永远记得一个事实:linux当中后缀名不是必须的,更多是为了便于区别。 从例子学习使用 tar进行文件打包 1.打包文件 tar -cf file.tar file1 file2 将file1和file2进行打包。-c表示进行打包,-f指定打包文档(file.tar) 2.解包文件 tar -xf file.tar -x表示解包,-f指定解包文档(file.tar) 压缩文件进行文件压缩 这里只介绍利用gzip压缩软件,事实上还有其他的压缩软件可以使用 1.压缩文件 gzip file.tar 2.解压文件 gunzip file.tar.gz 直接利用tar进行打包与解压 1.压缩文件 tar -czvf file.tar.gz file1 file2 -c,-f已经介绍过。-z表示使用的压缩是gzip压缩,-v表示显示所有过程 2.解压文件 tar -xzvf file.tar.gz 现在你应该理解了压缩与解压阶段各种参数的意义。 注意:-f后面必须接文档名,所以作为最后一个参数

February 14, 2022 · yunlang

在linux上游玩星际争霸2

简介 限制想要将工作从windows迁移到linux上的一个方面就是游戏。Steam已经通过proton给到了游戏玩家更多的选择。暴雪尚未出现linux版本,但好在还有wine的存在。通过lutris,现在你可以更轻松地在linux上享受游戏。 我会尽量给出官方文档,以便于不同时间的不同用户进行操作时可以减少错误。 操作系统:manjaro 显卡:Nvidia no-free驱动 步骤 1.安装合适的Gpu驱动 https://github.com/lutris/docs/blob/master/InstallingDrivers.md lutris为我们创建了一个良好的文档说明。你可以选择与你电脑相符的介绍并继续操作。对我的系统manjaro而言,我已经在安装时选择了no-free驱动,因此已经有了一套正确的驱动支持。 安装wine https://github.com/lutris/docs/blob/master/WineDependencies.md 同样,选择你的发行版并按步骤进行操作,这里以我的系统manjaro为例。 修改/etc/pacman.conf,添加[multilib]启动multilib仓库,在文件中添加以下内容: /etc/pacman.conf -------------------------------------------------------------------------------------- [multilib] Include = /etc/pacman.d/mirrorlist 更新pacman仓库 sudo pacman -Syu 安装wine,要安装的包有点多,但其实很多你已经安装过了,全部的依赖安装可以避免之后出现奇奇怪怪的问题。 sudo pacman -S --needed wine-staging giflib lib32-giflib libpng lib32-libpng libldap lib32-libldap gnutls lib32-gnutls \ mpg123 lib32-mpg123 openal lib32-openal v4l-utils lib32-v4l-utils libpulse lib32-libpulse libgpg-error \ lib32-libgpg-error alsa-plugins lib32-alsa-plugins alsa-lib lib32-alsa-lib libjpeg-turbo lib32-libjpeg-turbo \ sqlite lib32-sqlite libxcomposite lib32-libxcomposite libxinerama lib32-libgcrypt libgcrypt lib32-libxinerama \ ncurses lib32-ncurses opencl-icd-loader lib32-opencl-icd-loader libxslt lib32-libxslt libva lib32-libva gtk3 \ lib32-gtk3 gst-plugins-base-libs lib32-gst-plugins-base-libs vulkan-icd-loader lib32-vulkan-icd-loader 以上,wine安装完成。 ...

January 23, 2022 · yunlang

数据流重定向

简介 数据流重定向是将某个指令执行后要输出在屏幕上的数据,传输到其他的地方。一是可以简化我们的屏幕输出, 去获取我们有用的数据。同时我们还可以将我们想要的数据存储下来。 你可以通过echo "123"和echo "123" > filename 去简单尝试一下这种方式的特点,第二种可以通过 查看新增的file文件观看内容。 标准输入输出与标准错误输出 基本使用 > 是我们实现这种数据流重导向所用的特殊字符,数据流重导向包括标准输入,标准输出和标准错误输出, 他们的规则如下所示: 名称 代码 符号 标准输入(stdin) 0 <或« 标准输出(stdout) 1 >或» 标准错误输出(stderr) 2 2>或2» > 和 » 的区别是 > 以覆盖的方法输出内容, » 则是以累加的方式输出内容。你可以自 己试一试。 标准输入的用法类似,可以尝试一下cat > file 尝试键盘输出,使用[ctrl]+d退出,然后看一下得到的 文件。 /dev/null 垃圾桶 在linux一切皆文件的哲学中 /dev/null是一个特殊的"装置" 你可以将任何你想忽略的内容导向到它,而这些 内容将彻底被丢弃。 特殊写法 如果我们想要将正确与错误数据写入同一个文件时,可能会发生数据交叉写入该文件内的情况,造成次序的错乱, 这个时候你可以使用 2>&1 和 &> 的语法。 find /home -name .bashrc > list 2> list <=错误 find /home -name .bashrc > list 2&>1 <=正确 find /home -name .bashrc &> list <=正确 2>&1 这种写法可以理解为将标准错误输出重定向到标准输出 &>file 这种写法可以理解为将标准输入和输出都重定向到文件file中 ls 2>1 测试一下,不会报没有2文件的错误,但会输出一个空的文件1; ls xxx 2>1测试,没有xxx这个文件的错误输出到了1中; ls xxx 2>&1测试,不会生成1这个文件了,不过错误跑到标准输出了; ls xxx >out.txt 2>&1, 实际上可换成 ls xxx 1>out.txt 2>&1;重定向符号>默认是1,错误和输出都传到out.txt了。 ...

January 23, 2022 · yunlang