- 博客(59)
- 收藏
- 关注
原创 C++11新特性
1.左值引用只能引用左值,不能引用右值。2.但是const左值引用既能引用左值也能引用右值。int main()//左值引用只能引用左值不能引用右值int a = 10;//ra1为a的别名//编译失败,因为10是右值//const左值引用既可以引用左值,也可以引用右值1.右值引用只能引用右值,不能引用左值2.但是右值引用可以引用move以后的左值int main()//右值引用只能引用右值,不能引用左值int a = 10;//无法将左值绑定到右值引用。
2024-03-15 10:08:45 694
原创 知识点汇总2
std::weak_ptr 是 std::shared_ptr 的一个伴随类,它允许你观察一个 std::shared_ptr 所管理的对象,但不会延长该对象的生命周期。安全性问题:如果 std::weak_ptr 观察的 std::shared_ptr 已经被销毁(即其指向的对象不再存在),那么尝试从这样的 std::weak_ptr 构造 std::shared_ptr 是不安全的,因为这将导致悬垂指针(dangling pointer),访问这样的指针会导致未定义行为。右值引用是实现移动语义的关键。
2024-03-09 16:57:39 979
原创 知识点汇总1
nice值的范围是从-20到+19。在C++中,std::bind 函数用于生成一个新的可调用对象,该对象在调用时会调用给定的函数或可调用对象,并可能带有预设的参数。这个过程是由汇编器完成的,它会把汇编代码转化为机器码,生成目标文件,这些文件是二进制格式的,比如Linux下的.o文件或Windows下的.obj文件。总的来说,nice值是Linux系统中用于调整进程优先级的一个工具,通过合理地设置nice值,可以有效地管理系统的资源分配,确保关键进程得到足够的处理器时间,同时限制资源密集型进程的影响。
2024-03-09 16:52:48 907
原创 位图和布隆过滤器
我们可以将原来一个位表示一个值,改为两个位表示一个值,如果出现两次及两次以上就用11来表示,如果只出现一次就用01表示,除此之外我们也可以设计一个类,类中成员为两个位图,通过两个位图来判断哪个数据出现一次,当n第一次出现时就把位图1第x位设为1,当第二次出现时,检查位图1中该数是否存在如果存在就把位图2也设为1。同问题1,我们把出现1次的数据在位图1和位图2中表示分别为0和1,出现两次在位图1和位图2中表示分别为1和0,出现两次以上在位图1和位图2中表示分别为1和1。将数字n对应的位置置为1。
2023-12-30 16:18:37 971
原创 C++哈希表(unordered_map和unordered_set)
哈希表封装unordered_map和unordered_set具体步骤一、哈希表类1.定义桶节点,桶节点中包含存储的值和指向下一个桶节点的指针2.定义哈希表类,类中成员变量分别为一个数组,数组中的值指向一个桶的节点指针3.各类成员函数实现,通过两个DefaultHashFunc函数来获取key值所对应的整型值二、迭代器1.迭代器类需要两个成员变量分别为哈希表指针和桶节点指针2.实现迭代器的++,==和!=,指针,引用等操作。
2023-12-29 19:30:54 1373
原创 C++笔试训练day_2
理解题意:本题意思就是这个无序序列,在不被改动的情况下,最少可以被分为几个非递增或非递减序列,比如1,2,2,3,2,3,3,1就可以被分为1,2,2,3,和2,3与1这三个序列。常量指针,指针所指空间的值不能发生改变,不能通过指针解引用修改指针所指空间的值,但指针所指空间可以发生改变。常量指针,该指针是一个常量,可以通过解引用改变指针所指空间的值,但是指针的指向不能发生改变。结合说明p是一个指针,剩下的是int,所以p是一个指向int类型的指针。p[10],本质是一个数组,数组里面存放的是指针。
2023-12-26 18:49:51 879
原创 封装map和set
这个节点可能存的是关键字K,也可能是键值对结构节点成员变量存储的数据要怎么设计呢?是存储K,还是呢?不怕,我们有模板参数,我们只需要传递给该节点一个类型就可以了,如果是set我们就传递K对应类型就可以了,如果是map我们就传给他一个pair类型T _data;, _col(RED)//新节点默认为红色因此如果是map这里的_data实例化出的类型就是pair,如果是set它的类型就是K为什么新插入的节点默认设为红色?
2023-12-26 18:34:57 950
原创 map容器的基本使用
map和set容器,multimap和multiset是树形结构的关联式容器,这四种容器底层原理都是红黑树,容器中的元素是一个有序序列。
2023-12-24 14:02:16 1323
原创 set容器的基本使用
map和set容器,multimap和multiset是树形结构的关联式容器,这四种容器底层原理都是红黑树,容器中的元素是一个有序序列。
2023-12-23 16:49:19 1054
原创 C++异常
我们在写程序的时候,难免会出现一些错误,但是对于C语言来说,我们处理错误的方式,过于粗暴,比如通过assert断言终端程序,或者把错误放到错误码中,显然他们是有缺陷的,不利于我们知道是那种错误,且放在错误码中的错误还需要我们自己去查找,因此在C++中推出了异常处理机制,try…尝试try捕捉一个异常,如果出现异常就去找匹配的catch,如果在当前函数没有找到匹配的catch,就继续向上寻找,直到找到匹配的catch,如果一直找到main函数还是没有找到匹配的catch就直接终止程序。
2023-12-23 16:48:39 433
原创 Linux多线程
我们以两个线程之间造成的死锁问题进行举例,例如线程A,B,此时线程A,B各分别拥有一个临界资源a, b,且对这两个临界资源我们都添加了锁来进行保护,然后线程A在执行过程中需要临界资源b,线程B在执行过程中需要临界资源a,在A去申请资源b的时候发现资源正在被线程B占用,因此线程A只能等待,直到线程B不再占用资源b,同理B也需要等到线程A不再占用资源a,但是线程A,B现在都不去释放他们所拥有的资源,造成线程A,B只能去等待的情况,我们称之为死锁。下面我们来学习一下互斥量的接口,创建,加锁,解锁,销毁等。
2023-12-22 17:01:40 1314
原创 Linux线程
一级页表中每个条目存放的是不同二级页表的起始地址,找到对应的二级页表后,在通过11-20位找到它在二级页表中对应的位置,二级页表中每个条目存放的是它在物理内存中对应的起始地址即找到对应的页框,而物理内存中每个页框大小为4KB,我们再通过21-32位,计算出虚拟地址在该页框中的偏移量。如果进程切换就要重新加载数据(页表和虚拟内存等),且CPU中通过cache来存储缓存的数据,如果是进程间的切换就要重新缓存,并将数据由冷变热,而线程之间的切换,数据基本是不变的,因此不用再重新热数据。不让相同的数据加载两份呢?
2023-12-22 17:01:14 1061
原创 C++笔试训练day_1
在本题中最重要的就是怎么进行分组,然后怎么取到每组里面的中位数:我们选择通过resize扩容vector然后输入数据,去对这组数据进行排序,而分组方式是第一组取一个最小值和最大的两个值,第二组取次小值和次大的两个值,一次类推,这样就保证了我们一定可以去取到次大的值。解题思路:利用哈希映射的特性来解决上述问题,就可以以O(n)的复杂度解决问题,先把不能出现的字符映射到hash表上,在对str1进行遍历,如果它在hash上对应的字符为0,就证明这个字符能出现。因此中位数就是和6,结果sum就是9。
2023-12-03 19:41:49 186 1
原创 Linux进程信号
它的参数act是一个s指向用户区的sigaction结构体(函数名和结构体名允许同名),该结构体存储的是我们在处理该信号时要怎么做的数据,其中成员sa_handler指向处理动作函数,成员sa_mask是一个阻塞信号集,当接收到sigaction第一个参数对应的信号时,sigaction函数就会把用户区的sigaction结构体数据添加到系统内核,接收到的这个信号会自动添加到阻塞信号集,我们要是想阻塞其它信号就直接将对应的信号添加到成员sa_mask信号集即可。
2023-12-03 18:30:24 182 1
原创 红黑树底层原理
红黑树也是一种二叉搜索树,只不过给这棵树上的节点带上了颜色,但是已经有了AVL树为什么还要搞出红黑树这个东西呢?首先AVL树和红黑树是同一量级的,查找一个值事假复杂度相同,但AVL树而言,控制严格平衡需要付出很大的代价,在插入和删除时需要进行大量的旋转。
2023-11-27 17:44:50 211
原创 Linux进程通信之共享内存
key是一个数字,这个值是随机的,关键是这个随机数在内核中具有唯一性,可以让他对不同的进程拥有唯一的标识,第一个进程创建出key之后,后面的进程只要有了这个key,就可以拿着这个key去和其它进程进行共享内存了。但是此时会有一个问题,就是共享内存对于不同进程而言不是同步的,即写进程还没写,读进程就从共享内存中读,此时读到的为空,或者上次的,就一直在那打印,因此我们要让进程同步,等写进程写入了,读进程才开始读,这里举个例子,我们可以通过管道来实现进程同步,因为read函数,如果没有读取到就会一直等待。
2023-11-23 19:22:25 132
原创 Linux进程间通信之匿名管道
我们知道当一个进程要执行一个事情时,一般它会创建一个子进程,并把这件事交给该进程让它去完成,现在我们有若干个任务要去让这个进程去完成,因此该进程就要去创建多个子进程,让他们分别去完成这些事,但是像这种每一次都要创建子进程的过程是很浪费时间的,操作系统是不会允许这种影响效率的事情发生的,那么我们要怎么提高效率呢?管道共享更确切的说应该是缓冲区共享,我们先来理解一下fork函数,一个进程fork出了子进程,两个进程之间的代码是共享的,数据是独有的,当其中一个进程的数据发生改变时,就会发生写时拷贝。
2023-11-19 13:28:58 115
原创 AVL树的底层实现
AVL树又称平衡二叉搜索树,相比与二叉搜索树多了平衡的概念,为什么要有平衡二叉搜索树呢?因为二叉搜索树可能会出现退化现象,导致左右子树高度相差较大,甚至退化成单链表的形式,因此我们提出了平衡二叉搜索树,可以有效地解决高度相差过大的情况,平衡二叉搜索树要求任意节点的左右子树高度相差不大于1.
2023-11-17 19:12:55 126
原创 Linux动静态库
动静态库其实在使用上基本类似,不同点是静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
2023-11-16 15:55:03 104
原创 Linux文件系统
我们经常听说分区,那么什么是分区呢?其中block[num]数组索引是分级的,比如当num等于15的时候,前12个存放的是一级索引,也就是存的数据块的编号里面放的就是数据,后面两个是二级索引,意思就是他存的数据块编号里面存的不是数据,仍然是多个数据块编号,最后一个放三级索引,就是二级索引里面存的也是多个数据块编号而不是数据,这样做的目的就是为了能够存储更多的数据,而不被写死导致最多只能存放15个块数据。},结构体里面存的是inode编号对应文件的属性,比如修改时间,所属组,权限,文件类型,引用计数,
2023-11-10 15:01:22 201
原创 Linux重定向和缓冲区
缓冲区分为内核缓冲区和应用层缓冲区,对于库函数会先把数据写入到应用层缓冲区,而系统调用一般是直接写到内核缓冲区,当写到应用层缓冲区又会分三种情况:直接刷新,行刷新,全缓冲。直接刷新就是不在应用层缓冲区等待,只要是有数据就直接刷新到内核缓冲区,对于行刷新就是只要遇到\n就向内核缓冲区进行刷新,全缓冲就是等缓冲区写满了才向内和缓冲区进行刷新。对于向屏幕打印时采用的是行缓冲,向文件写入时采用的是全缓冲对于fflush函数就是直接刷新向内核缓冲去写入,因此我们可以断定,该函数一定在底层会调用write函数。
2023-11-09 14:26:42 219 1
原创 深入理解IO底层
mode有模式的意思,用于设置要被创建的这个文件的权限,如果要被写入的文件已经有了,则这个参数就不没用了,上述代码中我们也用到了权限掩码umask,它默认是0002,我们在创建时给的参数是0446,如果想要结果就是0446,那么就需要把这个掩码改为0000,我们有两种做法,一种是改变整个环境的掩码,另一种就是改变该进程中的掩码,上面函数中设置的umask(0)就是只在这个进程中有效。传递的参数fd,其实就是文件描述符,而文件描述符中0,1,2分别对应的就是标准输入,标准输出,标准错误。
2023-11-06 10:22:26 94
原创 搜索二叉树
搜索二叉树中另一个特点就是没有重复的值,如果插入的节点在该树中已经存在,那么就不会再进行插入,如果不存在那么就在树的叶子结点的null节点处,找到合适的位置进行插入。既有左孩子又有右孩子:两种解决方案(假定左子树比该节点小,右子树比该节点大),1.让左子树的最大节点代替该位置2.让右子树最小节点代替该位置。它的特点就是任意节点的左右子树,一个子树全都比该节点的值大,另一个子树全都比该节点的值要小。无孩子节点,只有左孩子,只有右孩子,左右孩子都有。只有左孩子节点:让左孩子节点代替该节点的位置即可。
2023-11-05 00:39:34 197 1
原创 C++适配器
底层就是把这个类重载了一个()运算符。在传这个参数时,我们可以自己实现一个仿函数去传,也可以使用库里面的。比如stack的push底层其实是通过调用deque的push_back()实现的,pop底层是通过调用deque的pop_back()实现的。对于queue的push底层是通过调用deque的push_front()实现的,pop是通过调用deque的1pop_front()实现的。这两个是库里面包含的两个仿函数,用于比较大小,去排序,值得注意的是这里的less指的是升序,而greater是指降序。
2023-11-04 01:57:04 163 1
原创 Linux进程等待
在进程回收等待的过程中,有两种方式,一种是阻塞式等待一种是非阻塞式等待,阻塞式等待,如果该进程未执行完退出,就等到该进程退出,非阻塞式等待,如果该进程还在运行,就不再等待该进程完成。进程在退出时,会返回退出码,而这个退出码一般是交给父进程,让关心它的父进程知道他办的事情怎么样了,在上述过程中我们一直都是使用echo $?当终止信号为0时,则表示正常终止,此时查看退出状态信息,这里的退出状态信息时可信的,当终止信号不为0时,说明是异常退出,此时就8-15位的退出状态就是不可信的。剩下的部分并没有被使用。
2023-11-03 14:25:17 77
原创 C++迭代器
迭代器有正向迭代器和反向迭代器两种,先来回顾一下正向迭代器,正向迭代器中begin()指向容器的第一个元素,end()指向容器的最后一个元素的下一个位置,而反向迭代器rbegin()指向最后一个元素,rend()指向第一个元素的前一个位置,接下来我们在list中通过正向迭代器改造出反向迭代器,首先我们要指明的是。迭代器本质上是指针,那么又是怎么做到返回的rbegin这个迭代器指针解引用时,值为容器的最后一个值而不是最后一个值的下一个值呢?此外重载的运算符++和–在底层对应的是正向迭代器的–和++
2023-11-02 21:35:18 134
原创 C++特殊类的设计
不管你将来是不是用这个实例对象,只要程序启动这个对象就被实例化出来,且全局始终只有这一个实例化对象。优点:简单缺点:可能会导致进程启动变慢,且如果有多个单例类对象实例,启动顺序不确定。如果这个单例对象在多线程高并发情况下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好。
2023-11-01 15:20:10 81
原创 Linux进程程序替换
1、函数名中带l,就是要我们以参数列表的形式传递命令行参数2、函数名中带v,就是要我们以指针数组的形式把参数传过去3、函数中带p,说明它会继承父进程的环境变量,因此可只需指明要去替换的可执行程序的文件名即可,函数会自己去找到该文件4、函数名中带e的,需要我们自己自定义设置环境变量,可以自己添加环境变量指针数组传过去,但这会覆盖继承的环境变量,如果想保留继承的环境变量,那么在当前进程putenv()对应的环境变量添加到当前进程的上下文(不会添加到父进程),再用全局变量environ传递过去即可。
2023-10-31 16:16:40 72
原创 Linux进程地址空间
2.页表也有一种权限管理,当你对数据区进行映射时,数据区是可以读写的,相应的在页表映射关系就是可读可写的,但是当你对代码区和字符常量区进行映射时,因为这两个区域只是可读的,相应的在也表中的映射关系中的权限就是可读的,如果你对这个区域进行了写,通过页表中的权限管理,操作系统就会直接将这个进程杀掉。上述代码,返回值有两个,因为分别为父子进程的返回值,且父子进程共用同一份代码和数据,这个我们在之前就了解过了,没什么问题,再来看下面的代码,稍加改动。此时可能你还会有些疑问,为什么要有虚拟地址?
2023-10-29 11:43:38 95
原创 C++多态
多态通俗来讲就是同一件事情,不同的人来做就会产生不同结果,例如学生,军人,儿童,成人等买票,不同的人买票的价格不同。多态是在不同继承关系的类对象,去调用同一函数产,生了不同的行为。比如Student继承了Person,Person对象买票全价,Student对象买票半价。因为只有基类的指针或引用既能指向父类又能指向子类,注意基类对象如果不强制转换是不可以赋给子类的对象,引用或指针的。
2023-09-12 09:35:33 350 1
原创 C++的list
节点类中存放的是数据,以及每一个节点的前后指针。注意这里的构造函数给的默认值为val = T(),给了一个匿名对象,如果是自定义类型,它就会调用对应的自定义类型的构造函数,当它为内置类型时也会调用它对应的构造函数,这里你可能会有疑问,内置类型不是没有默认构造函数吗?这是因为C++11对这里进行了特殊处理,内置类型也给了默认构造函数。初次看到这个迭代器类,你会感到很茫然,为什么要给三个模板参数,并且这三个模板参数,在学习后你发现这三个模板参数T都是相同的,不过是T,T*,T&,直接返回函数对应的这三个类型
2023-09-12 00:41:53 540
原创 C++继承
其它的继承可遵循public>protected>private取其中小的方式进行访问,比如基类中成员为protected,子类以public方式进行继承,那么在子类中该成员的访问限定符就为两者中小的那个protected。友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员,友元函数是你父亲的朋友,别人不一定知道他是你的朋友,要想让别人知道是你的朋友,那么你就要去声明他。例如B,C都继承A,D继承B也继承C,那么就要在B,C类继承A的时候在类A名前加virtual。组合是一种has-a的关系。
2023-08-17 11:08:59 400
原创 C++的stack和queue+优先队列
适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。
2023-08-14 20:37:44 716
原创 C++的vector
在对容器进行insert、resize、reserve、assign、push_back等操作时会导致_capacity发生变化,在容量发生变化时,可能会出现异地扩容,这就会导致原来的迭代器指向已经被释放的空间,从而导致程序崩溃。以上述程序为例,如果是在VS中只要是在删除操作后,迭代器就会失效,如果不给迭代器重新赋值,直接再次使用迭代器就会强制报错,而在Linux中不一定会报错,因为可能会误打误撞的让程序可以运行,结果也会正确。2.指定位置元素的删除操作----erase。使用迭代器进行初始化构造。
2023-08-06 18:34:20 346
原创 Linux基本工具
按[i]切换进入插入模式,按“i”进入插入模式后是从光标当前位置开始输入文件按[a]进入插入模式之后,是从目前光标所在位置的下一个位置开始输入文字按[o]进入插入模式之后,是从当前光标所在行后插入新的一行,然后从行首开始输入文字按[O]进入插入模式之后,是从当前光标所在行前插入新的一行,然后从行首开始输入文字完成到预处理阶段就停下来加选项-E生成的对应文件后缀为.i完成到编译阶段就停下来加选项-S生成的对应文件后缀为.s完成到汇编阶段就停下来加选项-c生成的对应文件后缀为.o。
2023-06-13 19:00:33 1189 3
原创 C++中string类的常用函数
引言:在C语言中对于字符串的一些操作,例如在字符串末尾增加字符,对字符串拷贝等,我们可以通过调用库中函数来完成这些操作,在C++中,我们把这些常规操作封装成了string类,可以通过类对象直接调用这些函数,使得更加符合了面向对象的思想。
2023-06-08 18:27:13 4308 1
原创 C++内存管理和模板
malloc只是开辟了一段Date这个对象大小的空间,并没有初始化,而通过new申请空间时它会自动调用这个对象的构造函数对它进行初始化,并且free也仅仅是释放这个对象的空间,如果成员变量中包含在堆上动态申请的空间例如栈,它并不会对栈进行释放,而delete会自动调用析构函数对成员变量中动态开辟的空间进行释放。
2023-05-25 16:30:46 822 3
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人