侯捷——2.C++标准库 体系结构与内核分析

news2024/9/22 21:25:52

侯捷——2.C++标准库 体系结构与内核分析

1. C++标准库 vs STL

在这里插入图片描述

在这里插入图片描述
C++标准库包含STL。标准库都用 std 这个命名空间包装起来。

2. STL体系结构基础介绍

在这里插入图片描述
allocators(分配器)是给containers(容器)分配内存的。当要创建容器时,必须先有分配器分配内存。在创建容器时,可以指定分配器,也可以不指定,编译器会默认指定分配器。

在这里插入图片描述

2.1 复杂度

在这里插入图片描述

2.2 迭代器采用前闭后开区间

在这里插入图片描述
begin()指向第一个元素,而end()指向最后一个元素的下一个元素。

2.3 range-based for statement(since C++11)

在这里插入图片描述

2.4 auto关键字

在这里插入图片描述

3. 容器——结构与分类(1)

在这里插入图片描述
循序式容器,是根据你放进去的顺序来决定顺序的。
Array、Vector和Deque的底部都是在内存中占用的空间都是连续的。
List和Forward-List都是空间可以不连续的。

在这里插入图片描述
关联式容器,就是Set/MultiSet和Map/Mulimap,底部实现都是红黑树。

关联式容器都是内部有序的,而Set和Map是内部元素不可重复的,MultiSet和MultiMap是内部元素可以重复的。

Unordered Containers(无序容器),内部元素都是无序的,底部实现是哈希表。

在这里插入图片描述

3.1 Deque

在这里插入图片描述
Deque(双向队列),其实它内部是有可能不连续的,但为了让它看起来是连续的,则每当读到一个buffer最后一个元素时,要自动跳到邻近buffer的第一个元素。

stack(栈)和queue(队列)底部都是deque实现的,只是限制了deque的进出元素的方式。
在这里插入图片描述
在这里插入图片描述
stack和queue是没有iterator的,因为stack是先进后出,queue是先进先出,如果有iterator的话,就有可能会通过iterator修改它们中间的值,从而破坏规则。

3.2 无序容器(unordered)

在这里插入图片描述
无序容器包括unordered_set、unordered_multiset、unordered_map和unordered_multimap。它们底部实现是哈希表,如上图,哈希表的位置称之为篮子。篮子的个数会随着元素的增加而扩充。
例如当篮子只有10个的话,当元素达到10个,篮子数量就会扩充到20个,然后把原来的元素打散,按照新的表达式计算出各个元素的新位置。

所以一般篮子的个数都会比元素的个数多。

4. 分配器(allocator)

容器的背后需要一个东西来支持它内存的使用,这个东西就是分配器。


容器的模板都有第二参数,就是分配器。但可以不指定,会自动使用默认的分配器。

4.1 用法

在这里插入图片描述
在这里插入图片描述

不推荐单独使用分配器。

5. OOP(Object-Oriented programming) vs GP(Generic programming)

5.1 OOP

OOP(面向对象编程)一般是将 datas(数据) 和 methods(方法)合并在一起的。
在这里插入图片描述
list无法使用全局的sort()。需要自己实现。
在这里插入图片描述

5.2 GP

GP是将数据和方法分开来的。
在这里插入图片描述
容器和算法要取得联系得通过迭代器。

vector和deque就可以使用全局的sort()

在这里插入图片描述
采用GP的好处:

  1. 容器和算法可各自工作,互不影响,用迭代器沟通即可。
  2. 算法通过迭代器确定操作范围,并通过迭代器取得容器中的元素。

如果类中有实现sort(),则使用自己类中的。如果没有,则使用全局的。

在这里插入图片描述

6. 操作符重载和模板(泛化、全特化、偏特化)

6.1 全特化

当某个类型有更好的处理方法时,可以使用特化。就是指定某种类型时,调用对应的方法。要注意特化的语法表示,如下图所示。
在这里插入图片描述

6.2 偏特化

在这里插入图片描述

7. 分配器(allocators)

分配器的好坏会影响容器的效率。因为分配器是为容器分配内存的,而容器中元素的进出都会关系到内存的分配。

7.1 先谈operator new()和malloc()

所有的内存分配动作最终都会跑到malloc()下去。

在这里插入图片描述
operator new()也不例外。malloc在分配内存时,会多分配出 32+4 字节的灰色部分,会两块红色的cookie部分,还有根据情况而定的绿色填充部分。所以当你想要分配的内存比较小的时候,灰色和红色这些内存是会固定分配的,所以会导致,实际上使用的内存占比比较小,而当你要申请的内存比较大的时候,则实际使用的内存占比就会比较大。

7.1 分配器的源码

以下是VC6低下的allocator的源码:
在这里插入图片描述
allocator两个比较重要的函数就是allocate()deallocate()allocate()底部会调用operator new(),而operator new()会调用malloc(),所以归根结底就是allocate()会调用malloc()。而deallocate()也同理,底部会调用operator delete(),而operator delete()底部会调用free()

分配器在申请和释放内存时都需要指定大小,这是很不方便的,释放时很难去记住当初申请的大小。所以一般不推荐直接使用分配器。

VC下的 allocator 没有特殊的设计,背后只是调用 malloc 和 free 来实现内存的分配和释放。

VC下、BC下和GNU下的allocator的实现都差不多。但GNU下实现的allocator不怎么会去使用它,而是使用alloc

在这里插入图片描述
alloc 的主要改变是为了避免每分配一个元素需要在该元素上下消耗的8byte的cookie(记录大小),因为每次malloc都带来额外的内存开销。每个元素根据是 8 的几倍挂到上图对应的区域。当对应倍数下的链表没有内存时,系统还是会使用 malloc 向系统申请一大片内存。当然一使用malloc就会有额外开销。

8. 容器之间的实现关系与分类

在这里插入图片描述
本图以缩排形式表达“基层与衍生层”的关系。这里所谓的衍生,并非继承而是复合。
例如set、map、multiset和multimap与rb_tree(红黑树)的关系就是复合关系,也就是set、map、multiset和multimap里有rb_tree,它们底部需要红黑树作为支撑。

9. 深度探索list

在这里插入图片描述
这里的 __list_node 节点设计中有一些小缺陷,该结构体左右节点指向的是 void* ,也就是在使用时还得注意转型。一般来说,节点两端指向的都是自己本身这种类型。

除了array和vector,其它容器的 iterator 都要自己通过写出 iterator 类来实现,才能使 iterator 变聪明,可以通过 ++ 而指向下一个。

9.1 list的iterator

在这里插入图片描述
iterator少不了操作符重载,因为要使它像指针。

operator++()是前置的++,相当于是i++;而为了区分前置跟后置,所以后置的加了一个参数,作为区分,这个参数是没有用到的,operator(int)

在这里插入图片描述
C++不允许连续两次后置++。
为了前置++可以两次,所以它的返回类型是引用。为了使后置++不可以两次,所以它的返回类型不是引用。

在这里插入图片描述

9.2 list不同版本的比较

在这里插入图片描述
在这里插入图片描述

10. 迭代器的设计原则和Iterator Traits的作用与设计

10.1 Iterator 需要遵循的原则

在这里插入图片描述
value_type 指的是容器的类型,如果容器的类型是int,则 value_type 为 int。
difference_type指的是两个iterator之间的距离,应该用什么类型来表现,如 unsigned_int。

迭代器需要回答算法的五个问题:
iterator 必须定义的五种类型,iterator_category(),difference_type,value_type,reference和pointer。以此来回答算法提出的问题。虽然reference和pointer从来没有被使用到。
在这里插入图片描述

ptrdiff_t是比编译器已经定义好了的,好像是unsigned_long。

当iterator不是一个class时,而是一个自然指针(相当于一种退化的iterator),这个时候算法想要问它问题,就问不出什么,为了解决这个问题,引入了trait。

10.2 Iterator Traits的作用与设计

在这里插入图片描述
Iterator Traits(萃取机)必须要能区分iterator到底是class类型的,还是不是class类型的。可以把迭代器放进萃取机,问它一些事情,比如问迭代器是哪种类型等。

traits相当于中介。

在这里插入图片描述

在这里插入图片描述

11. vector深度探索

容器是一个前闭后开的区间。finish和end_of_storage都指向下一个。
在这里插入图片描述
vector有三个iterator变量,分别是start(指向容器的开始)、finish(指向容器中最后一个元素的下一个)和end_of_storage(指向容器的末端的下一个)。当finish与end_of_storage相等时,如果还继续放入元素,则空间会以两倍原先的空间进行扩展,而这种扩展不会在原来的地方进行扩展,而是在别处寻找两倍的空间进行扩展。

11.1 源码(G2.9)

在这里插入图片描述
容器只要是存储在连续空间的就会提供operator[]

在这里插入图片描述
在这里插入图片描述
每次的扩展就会引发大量的拷贝动作,而拷贝就会调用拷贝构造函数。而原来的空间也要释放,所以会调用析构函数。所以每次的扩展会调用大量的拷贝构造函数和析构函数,这是一个大的成本,在使用vector时要注意。

11.2 vector的迭代器

vector的迭代器不用设计得太复杂,因为vector内存是连续的,不用像list一样,把iterator单独设计成一个class,原因是list是内存不连续的。而vector的iterator只需要设计成指针就行了。
在这里插入图片描述

11.3 G4.9版本

在这里插入图片描述
在这里插入图片描述
G4.9的iterator是一个class,不是一个单纯的指针。
在这里插入图片描述

12. array、forward_list(单向链表)深度探索

12.1 array

在这里插入图片描述
G4.9 版本
在这里插入图片描述

12.2 forward_list(单向链表)

在这里插入图片描述

13. deque(双向队列)、stack和queue的深度探索

在这里插入图片描述
deque的底层,有一个vector(也就是图中的map)用来装指针,指针指向buffer(缓冲区),当deque想往前扩充时,只需要创建一个buffer,然后在vector前面的空地方用一个指针指向它就好。往后扩充也是同理。

deque是一个分段连续的容器,连续是假象,分段是事实。

13.1 源码

在这里插入图片描述
size_type类型的元素大小为4。

一个deque对象本身占40字节(两个iterator,2*16,加上4+4)。

13.2 deque的iterator

在这里插入图片描述

13.3 deque< T >::insert()

因为deque可以两端插入,所以在进行元素插入时可以比较聪明。当插入的位置处于deque所有元素的偏前面时,移动的是将插入位置前面的所有元素,而不是去移动后面的,这样做的目的是提高效率,因为每次的移动都需要调用构造函数和析构函数。
在这里插入图片描述

在这里插入图片描述

13.4 deque如何模拟连续空间

全是deque iterators的功劳。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
set_node()也可以用来往前跳。

+=和+是实现iterator进行多个元素的跳转。
在这里插入图片描述
进行多个元素的跳转有两种情况,第一种是要跳的距离还是在同一个缓冲区内,这种情况就比较简单;第二种情况是跳的距离要跨越缓冲区,这时就得继续需要跨越多少个缓冲区,如何在存储缓冲区指针的vector种,先移动对应的几个,到达对应的缓冲区,然后再移动到对应的位置。

在这里插入图片描述

G4.9版本
在这里插入图片描述
在这里插入图片描述

13.5 queue的源码

在这里插入图片描述
stack和queue底部容器都是deque,只是封住某些端口。

13.6 stack的源码

在这里插入图片描述

13.7 queue和stack,关于其iterator和底层结构

在这里插入图片描述
queue和stack的底层结构默认是deque,但也可以选择list。速度的话,是deque比较快。

还有一个需要注意的点就是,stack和queue都不允许遍历,所有也不提供iterator。 因为一个是先进后出,一个是先进先出,如果允许在指定位置进行插入的话,就会干扰到原来的模式。

在这里插入图片描述
注意: stack还可以选择vector作为底层结构,而queue不能。

在这里插入图片描述
还有就是stack和queue不可以选择set或map作为底层结构。因为只要一些函数无法调用,就没办法实现原本的模式。

14. 容器rb_tree(红黑树)

在这里插入图片描述
我们不应该使用 rb_tree 的 iterators 改变元素值(因为元素尤其独特的排列规则),例如图中 6 改成 60 是不被允许的。但编程层面并未杜绝此事。不过这样设计是正确的,因为 rb_tree 是为 set 和 map 服务(作为其底部支撑),而 map 允许元素的 data 部分被改变,只有元素的 key 才是不可被改变的。

rb_tree 提供两种插入操作:insert_unique() 和 insert_equal()。前者表示插入的 key 在整个 tree 中是独一无二的,否则插入失败;后者表示插入的 key 是可以重复的。

在这里插入图片描述
第三个模板参数KeyOfValue表示从value中取出key的方式。

在这里插入图片描述
size_typeunsigned_int,所以大小为4字节;link_type是指针,所以大小也为4字节;key_compare是一种仿函数,仿函数是一个大小为0的class,但会给它分配1字节的大小。所以rb_tree整个类的大小为9,编译器的默认对齐方式为4字节,所以它的大小为12字节。

G4.9的红黑树
在这里插入图片描述

15. 容器set和multiset

value包含key和data。
set/multiset 元素的 value 和 key 合一:value就是key,相当于就是没有data。

在这里插入图片描述

在这里插入图片描述
identity 就是将key看成value,取value时,返回key。

15.1 set in VC6

在这里插入图片描述
VC6里的_Kfn等同于identity()。

16. 容器map和multimap

在这里插入图片描述

在这里插入图片描述
map不允许通过迭代器来修改key,它是通过在pair中,直接让key为const。

16.1 map in VC6

在这里插入图片描述
VC6里没有select1st(),这个函数的作用是查找容器中的对应的key。

16.2 multimap

在这里插入图片描述
multimap不可使用 [] 做插入操作。
在这里插入图片描述
当用[]想map插入元素时,首先会先检查map里有没有该value,如果有,则用 iterator 指向其中第一个value(如果是multimap的话,有多个value相等的);如果没有,则 iterator 会找到最适合插入该value的位置。

17. 容器hashtable(哈希表)

在这里插入图片描述

18. 迭代器的分类

在这里插入图片描述
算法看不见容器,对其一无所知。所以,它所需要的一切信息都必须从迭代器(iterators)取得,而 iterarors (有containers提供)必须能完成 algorithm 的要求,才能搭配该 algorithm 的所有操作。

在这里插入图片描述
迭代器的分类如上图所示,使用结构体来表现,而且有的还是继承关系。

注意上面的连线,Forward-List(单向链表)用的迭代器是forward_iterator_tag(单向迭代器);Array、Vector、Deque(虽然它底层不是完全连续) 用的迭代器是random_access_iterator_tag(随机访问迭代器);List(双向链表)、Set/Multiset、Map/Multimap 用的迭代器是 bidirectional_iterator_tag(双向迭代器)。

unordered_set/multiset 和 unordered_map/multimap 视情况而定。

18.1 自己编写能够得到容器迭代器类型的代码

当我们想要用代码来识别当前容器的迭代器是什么类型时,可以使用下图这种方法,使用萃取机(iterator_traits< I >::iterator_category)来获得当前容器的迭代器的类型。根据编写函数重载的函数,就可以输出对应容器迭代器的类型。
在这里插入图片描述
注意: istream_iterator 的类型就是input_iterator;ostream_iterator 的类型就是 output_iterator。

18.2 利用标准库自身的标识(各种容器的迭代器的iterator_category 的typeid)

要记得包含同文件 #include< typeinfo > 。
在这里插入图片描述

18.3 迭代器分类对算法的影响

18.3.1 一个例子(求两个迭代器之间的距离)

在这里插入图片描述
distance()是一个算法,用于计算两个迭代器之间的距离。但它的距离的类型不是 int,迭代器中有一种数据类型是用来代表两个迭代器之间的距离的(difference_type)。所以要把我们的迭代器类型传给萃取机,让萃取机帮我们找到对应的 difference_type,所以这个函数的返回类型是 iterator_traits< InputIterator >::difference_type。

它有一个对外开放的版本,底部调用就有两个版本,根据迭代器的类型来选择对应的函数。注意上面代码中的 category() ,这种语法的使用,就是一个临时对象,type name加上括号可以代表一个临时对象。

在数据很多的情况下,使用第二个 distance 会比第一个快很多。

这这里就可以看出,为什么迭代器类型要用结构体来表示而不是用枚举类型?
使用结构体来表示迭代器类型可以方便地封装相关数据和行为,并实现多态性,从而提高代码的灵活性和可复用性。例如上面的例子,五种迭代器类型,而只有两种迭代器类型的函数,这时,如果是 forward_iterator_tag 或者是 bidirectional_iterator_tag 类型就会直接调用第一种函数。

18.3.2 一个例子(让迭代器移动对应的距离)

在这里插入图片描述
跟上面是一样的道理。

18.3.3 另一个例子(拷贝函数)

在这里插入图片描述
上面memmove()是C语言的一个拷贝字节的函数,属于低阶动作,速度较块;当最后判断是< T*,T* >或< const T*,T* >的话,就会经过 Type Traits 的判断,如果是不重要的(has trivial op=())话,就调用 mommove()处理,如果是重要的就用__copy_d()处理。

总之就是根据参数的类型去调用最快的函数。

18.3.4 另一个例子(destroy)

在这里插入图片描述

19. 算法源码剖析(11个例子)

20. 仿函数(Functors)

functors 是六大部件中大多时候比较会自己编写的一种,就是写一些能融入到STL(标准库)里的东西就是这种东西。 仿函数又称函数对象,专门为算法服务,当算法需要一些指定的规则(操作)时,就可以使用functors;例如,sort算法中我们可以自己指定排序的顺序,就可以创建一个functors,然后把functors传进去。

在这里插入图片描述

functors有三大类:算术类、逻辑运算类和相对关系类(比大小)。仿函数的特点就是重载小括号运算符。

在这里插入图片描述

20.1 举个例子

在这里插入图片描述
当我们自己实现的仿函数不继承STL里的类时就没有融入到STL里去,其实标准库中的 functors 都会有继承关系,虽然上面 myobj 和 less< int >() 实现的效果是一样,但 myobj 没有继承 STL 中的 binary_function或unary_function,就没有融入到STL中去,虽然上面执行没问题,但如果再执行某些操作,就会出现问题。因为它没有达到STL的全部要求。

20.2 为什么要继承(functors的可适配条件)

在这里插入图片描述
STL规定每个可适配的函数都应挑选上面两个其中的一个来继承,因为函数的适配器(Adapter)会向仿函数提问题。可适配的意思就是可以被修改以达成某种操作。

unary_function适合单操作数的情况,binary_function适合双操作数的情况。这两个类都没有成员变量和成员函数,所以理论上大小为0,但编译器会让它为1。当它们作为父类被继承时,给子类增加的大小就为0。

在这里插入图片描述
所以 less 继承 binary_function 后没有任何坏处,所增加的大小为0,而且有了 binary_function 里的三种数据类型,这三个数据类型可以回答适配器的问题。

所以当我们想要我们写的 functors 可以被修改,被适配就需要选择上面两种中合适的一种去继承。

总结: 仿函数就是一个类或结构体里面重载小括号,这样的类或结构体创建出来的对象就叫做函数对象或仿函数。在大大小小的算法中,我们为了搭配算法就会写出相应的仿函数出来。但如果我们没有去继承上面两种类的话,在未来就没有被改造的机会。如果我们想要我们写的 functors 能融入到STL的体系中去,就必须选择其中合适的一种去继承。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C# Onnx Yolov8 Detect 印章 指纹捺印 检测

应用场景 检测文件中的印章和指纹捺印&#xff0c;用于判断文件是否合规&#xff08;是否盖章&#xff0c;是否按印&#xff09; 效果 项目 代码 using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using System; using System.…

debian 10 安装apache2 zabbix

nginx 可以略过&#xff0c;改为apache2 apt updateapt-get install nginx -ynginx -v nginx version: nginx/1.14.2mysql 安装参考linux debian10 安装mysql5.7_debian apt install mysql5.7-CSDN博客 Install and configure Zabbix for your platform a. Install Zabbix re…

Failed to run the WC DB work queue associated with 错误的解决

步骤&#xff1a; 1、”文件夹选项"中&#xff0c;显示所有隐藏的文件夹及文件&#xff0c;操作后&#xff0c;能看到隐藏的.svn文件夹下的wc.db文件了 2、到官网下载 sqlite 如果是Windows系统&#xff0c;下载Precompiled Binaries for Windows 下红框中版本 3、用sq…

把HexMergeCmd集成到右键菜单里

1. 复制HexMergeCmd到C盘Program Files 2. 双击“add.reg”&#xff0c;添加注册表项 Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\Directory\Background\shell\HexMergeCmd] "HexMergeCmd" "Icon""C:\\Program Files\\HexMergeCmd\\He…

Leetcode刷题详解——山脉数组的峰顶索引

1. 题目链接&#xff1a;852. 山脉数组的峰顶索引 2. 题目描述&#xff1a; 符合下列属性的数组 arr 称为 山脉数组 &#xff1a; arr.length > 3存在i(0 < i < arr.length - 1&#xff09; 使得&#xff1a; arr[0] < arr[1] < ... arr[i-1] < arr[i] arr[…

TensorFlow图像多标签分类实例

接下来&#xff0c;我们将从零开始讲解一个基于TensorFlow的图像多标签分类实例&#xff0c;这里以图片验证码为例进行讲解。 在我们访问某个网站的时候&#xff0c;经常会遇到图片验证码。图片验证码的主要目的是区分爬虫程序和人类&#xff0c;并将爬虫程序阻挡在外。 下面…

计算机网络——计算机网络体系结构(4/4)-计算机网络体系结构中的专用术语(实体、协议、服务,三次握手‘三报文握手’、数据包术语)

目录 分类一——实体 实体 对等实体 分类二——协议 协议 协议的三要素 分类三——服务 服务 服务访问点 数据包术语 计算机网络体系结构中的专用术语 本篇所讲的专用术语来源于OSI的七层协议体系结构&#xff0c;但也适用于TCP/IP的四层体系结构和五层协议原理体系…

Qt中的单例模式

QT单例类管理信号和槽函数 Chapter1 Qt中的单例模式一、什么是单例模式&#xff1f;二、Qt中单例模式的实现2.1、静态成员变量2.2、静态局部变量2.3、Q_GLOBAL_STATIC 宏实例2 三、使用场景四、注意事项 Chapter2 QT单例类管理信号和槽函数一、创建单例类二、主界面添加组件三、…

原始航片匀色调色方法

使用PhotoRC 2.0软件&#xff0c;对原始航片进行批量匀色&#xff0c;可以自动处理和人机交互&#xff0c;保留exif信息。 软件下载链接&#xff1a; https://pan.baidu.com/s/1Jj4cMpq8xzYvSa1hhozH-g?pwdndfm 提取码&#xff1a;ndfm

Spring Boot中使用JSR-303实现请求参数校验

JSR-303是Java中的一个规范&#xff0c;用于实现请求参数校验。它定义了一组注解&#xff0c;可以应用于JavaBean的字段上&#xff0c;用于验证输入参数的合法性。下面是一些常用的JSR-303注解及其介绍&#xff1a; NotNull&#xff1a;用于验证字段值不能为null。 NotEmpty&a…

RT-Thread 5. ENV添加自定义模块

代码 /* file: hello.c */ #include <stdio.h> #include <finsh.h> #include <rtthread.h> int hello_world(void) {rt_kprintf("Hello, world!\n");return 0; } MSH_CMD_EXPORT(hello_world, Hello world!)/* file: hello.h */ #ifndef _HELLO_H…

03 vi编辑器

vi编辑器的三种模式: 不同的模式下机键动作解释的意义是不一样的 编辑模式 插入模式 末行模式 文件的打开和关闭保存 移动光标

专业135总分400+西安交通大学信息与通信工程学院909/815考研经验分享

今年初试发挥不错&#xff0c;400&#xff0c;专业课135&#xff0c;将近一年复习一路走来&#xff0c;感慨很多&#xff0c;希望以下经历可以给后来的同学提供一些参考。 初试备考经验 公共课&#xff1a;三门公共课&#xff0c;政治&#xff0c;英语&#xff0c;数学。在备考…

AST反混淆实战|找出某里滑块226混淆代码隐藏的字符串

关注它&#xff0c;不迷路。 本文章中所有内容仅供学习交流&#xff0c;不可用于任何商业用途和非法用途&#xff0c;否则后果自负&#xff0c;如有侵权&#xff0c;请联系作者立即删除&#xff01; 1. 常见的字符串 在还原控制流之后&#xff0c;接下来的动作就是还原字…

高效翻译工具GPT插件的使用教程

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

【语义分割】语义分割概念及算法介绍

文章目录 一、基本概念二、研究现状2.1 传统算法2.2 深度学习方法 三、数据集及评价指标3.1 常用数据集3.2 常用指标 四、经典模型参考资料 一、基本概念 语义分割是计算机视觉中很重要的一个方向。不同于目标检测和识别&#xff0c;语义分割实现了图像像素级的分类。它能够将…

【【萌新的FPGA学习之Vivado下的仿真入门-2】】

萌新的FPGA学习之Vivado下的仿真入门-2 我们上一章大概了解了 我们所需要进行各项操作的基本框架 对于内部实现其实一知半解 我们先从基本的出发 但从FPGA 了解一下 vivado下的仿真入门 正好帮我把自己的riscV 波形拉一下 行为级仿真 step1: 进入仿真界面&#xff1a;SIMULAT…

凉鞋的 Unity 笔记 204. 语句

204. 语句 在上一篇&#xff0c;我们接触了三种常见的类型&#xff0c;如下所示&#xff1a; 这样我们算是对变量进行了一个入门年了。 其实我们除了变量&#xff0c;我们还接触了一个叫做语句的概念。 我们可以看下代码&#xff1a; using System.Collections; using Syst…

四川云汇优想教育咨询有限公司电商服务正规吗

随着抖音等短视频平台的火热&#xff0c;越来越多的消费者选择在平台上购物。四川云汇优想教育咨询有限公司也推出了抖音电商服务&#xff0c;但它的服务是否正规呢&#xff1f;本文将为您揭开真相。 首先&#xff0c;我们先来了解一下四川云汇优想教育咨询有限公司。这是一家致…

基于Java的足球赛会管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…