C++第二十二弹---vector深度剖析及模拟实现(下)

✨个人主页: 熬夜学编程的小林
💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】
目录
1、容量操作
2、内容修改操作
3、打印函数
4、迭代器失效
4.1、什么是迭代器失效
4.2、哪些操作会引起迭代器失效
总结
1、容量操作
size()、capacity()
获取容器的有效数据个数(连续内存空间的指针相减计算的就是间隔的元素个数)和分配给当前空间的大小,以元素个数表示。
size_t size() const
{return _finish - _start;
}
size_t capacity() const
{return _endofstorage - _start;
}
reserve(size_t n)
扩容。如果n大于当前容量则扩容,小于等于当前容量则不处理。
void reserve(size_t n)//将容量个数扩大到n
{if (n > capacity())//大于容量才扩容{size_t old_size = size();T* tmp = new T[n];memcpy(tmp, _start, sizeof(T) * size());delete[] _start;//加[]_start = tmp;//_finish = _start + size();//_start的地址改变了 size()结果变化_finish = _start + old_size;_endofstorage = _start + n;}
}
这里我们开空间完成的是一个深拷贝的过程,用 memcpy 将旧数组中的数据拷贝到新数组,但是memcpy 在这里基于字节的拷贝,即浅拷贝,那么,如果我们vector实例化为string类,这里string类进行浅拷贝会涉及到二次释放等问题。

解决办法:
通过一个循环,使用赋值操作符(自定义类型会调用赋值操作符重载)逐个拷贝旧数组中的元素到新数组。
void reserve(size_t n)//将容量个数扩大到n
{if (n > capacity())//大于容量才扩容{size_t old_size = size();T* tmp = new T[n];for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i];//调用赋值操作符重载,深拷贝}delete[] _start;//加[]_start = tmp;//_finish = _start + size();//_start的地址改变了 size()结果变化_finish = _start + old_size;_endofstorage = _start + n;}
}

注意:
需要提前计算原空间的大小,防止后面计算的大小是错误的,因为扩容的时候_start指针会修改指向,而_finish还指向原空间。
resize(size_t n)
调整容器的大小,使其包含n个元素。
如果n小于当前容器大小,则内容将减少到其前n个元素,删除超出的元素(并销毁它们)。
如果n大于当前容器大小,则通过在末尾插入所需数量的元素来扩展内容,以达到n的大小。如果指定了val,则将新元素初始化为val,否则初始化为缺省值。
如果n也大于当前容器容量,则自动重新分配所分配的存储空间。
void resize(size_t n,const T& val=T())//将容量修改为n个,并初始化为val
{if (n > capacity()){//扩容reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}else{//删除_finish = _start + n;//更改_finish位置即可,一般不缩容}
}
注意:
当 n 小于当前容量时,只需修改 _finish 指向即可,一般情况不缩容,如需缩容,可以调用shrink_to_fit()缩容函数。
2、内容修改操作
push_back()
尾插数据。即在_finish位置插入数据,在插入数据之前需要判断空间是否已满。
void push_back(const T& val)
{if (_finish == _endofstorage)//扩容{reserve(capacity() == 0 ? 4 : 2 * capacity());}*_finish = val;++_finish;
}
pop_back()
尾删数据(有数据才能删)。删除最后一个数据,修改_finish指向即可。
void pop_back()
{assert(!empty());--_finish;
}
empty()
判断容器是否为空(判断_start与_finish指向是否一致),为空返回true,否则返回false。
bool empty()
{return _start == _finish;
}
insert()
在pos位置插入数据。
1.使用断言保证在[_start,_finish]区间插入数据
2.判断是否需要扩容,扩容则可能出现迭代器失效情况,则需要提前计算pos 位置与 _start之间的距离。
3.将[pos,_finish)之间的数据都向后挪动一步,再pos位置插入数据。
4.最后返回新的pos位置。
iterator insert(iterator pos, const T& val)//在pos位置插入val
{assert(pos >= _start);assert(pos <= _finish);//扩容if (_finish == _endofstorage){size_t len = pos - _start;//标记pos与原数组起点的长度reserve(capacity() == 0 ? 4 : 2 * capacity());pos = _start + len;//扩容_start的指向修改,pos也需修改}//移动数据iterator it = _finish - 1;while (it >= pos){*(it + 1) = *it;--it;}//填充数据*pos = val;++_finish;return pos;//返回新的pos位置
}
erase()
删除pos位置的数据。
1.使用断言保证在[_start,_finish)区间删除数据,此处跟插入不同,不能删除_finsih位置数据
2.将[pos + 1,_finish)之间的数据都向前挪动一步。
iterator erase(iterator pos)//删除pos位置数
{assert(pos >= _start);assert(pos < _finish);//iterator it = pos;iterator it = pos + 1;while (it < _finish){//*it = *(it + 1);//it = pos; 越界*(it - 1) = *it;it++;}--_finish;return pos;
}
erase 返回值是一个迭代器,指向原来pos位置的下一个位置,即删除操作之后的pos位置。
push_back() pop_back()
尾插和尾删函数,使用insert()和erase()函数调用。
void push_back(const T& val)
{insert(end(), val);//在end()位置插入数据
}void pop_back()
{erase(end() - 1);//删除end()前面位置数据
}
3、打印函数
print_vector()
打印vector容器的数据(任意类型)。
template<class T>//函数模板
void print_vector(const vector<T>& v)
{//前面加typename则没有问题,表示iterator是一个类型//typename vector<T>::iterator it = v.begin();auto it = v.begin();//此处使用auto则可以避免此问题while (it != v.end()){cout << *it << " ";it++;//指向下一个位置}cout << endl;
}
注意:
显示访问迭代器时,需要在前面加关键字typename保证iterator是一个类型,或者直接使用auto。
4、迭代器失效
4.1、什么是迭代器失效
迭代器的作用:主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装。
迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。我们可以从以下三步进行分析:
- [1]迭代器的本质就是指针,迭代器失效就是指针失效。
- [2]指针失效:指针指向的空间是非法的。
- [3]指针指向非法空间:指向了被释放的空间 或者 越界访问 。
4.2、哪些操作会引起迭代器失效
- 所有可能会引起扩容的操作都可能会导致迭代器失效。如:resize、reserve、insert、assign、push_back等 -------------- 野指针引起的迭代器失效
- 指定位置的插入和删除都会都可能会导致迭代器失效。如: insert 、erase ----------------- 迭代器指向的位置意义发生改变
注意:
上述可能会引起迭代器失效的问题,代码中基本已经解决,如果uu们发现解决的有问题可以私信博主喔!!!
总结
本篇博客就结束啦,谢谢大家的观看,如果公主少年们有好的建议可以留言喔,谢谢大家啦!
相关文章:
C++第二十二弹---vector深度剖析及模拟实现(下)
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】 目录 1、容量操作 2、内容修改操作 3、打印函数 4、迭代器失效 4.1、什么是迭代器失效 4.2、哪些操作会引起迭代器失效 总结 1、容量操作 size()…...
GD32F470+lwip 丢包问题分析及解决
最近在用GD32和管理机之间用TCP协议开发一个功能,功能都没问题,后面跑大量发包时候的连续测试时,总是会出现偶发性的,大概几分钟到数十分钟的一次丢包。尽管在应用层做了超时机制,一旦超时就会重新建立socket链接并重新…...
好用的电子杂志制作平台分享
随着数字媒体的发展,电子杂志逐渐成为了一种流行的新媒体形式。它不仅能够吸引读者的眼球,还能够帮助创作者展示自己的才华。现在,许多电子杂志制作平台应运而生,让创作者可以轻松地制作出高质量的作品。 今天就给大家推荐一款好用…...
“云原生安全:构建弹性且安全的云上环境的关键要素“
云原生安全是指在设计和实施云原生应用时,从一开始就将安全性融入到每一个环节,确保云环境既具备弹性又安全可靠。构建一个既弹性又安全的云上环境,关键要素包括以下几个方面: 1. 微服务架构:采用微服务架构可以提高系…...
燃气安全阀检验维修:守护家庭安全的必备知识
燃气作为现代生活中不可或缺的重要能源,其安全使用直接关系到人民群众的生命财产安全。 燃气安全阀作为保障燃气系统安全运行的关键部件,一旦发生泄露,必须迅速采取有效措施进行排查、检验、维修,并建立长效机制进行预防和维护。…...
【JavaEE】多线程(1)
🎆🎆🎆个人主页🎆🎆🎆 🎆🎆🎆JavaEE专栏🎆🎆🎆 🎆🎆🎆计算机是怎么工作的🎆dz…...
相对位姿估计
相对位姿估计 示意图 理论推导 离线数据库: P的位置 P [ X , Y , Z ] T P[X,Y,Z]^{T} P[X,Y,Z]T 相机内参 k 1 k_{1} k1 安卓手机: 相机内参 k 2 k_{2} k2 两个像素点位置 : p 1 和 p 2 p_1和p_2 p1和p2 公式一:…...
记一次 .NET某工业设计软件 崩溃分析
一:背景 1. 讲故事 前些天有位朋友找到我,说他的软件在客户那边不知道什么原因崩掉了,从windows事件日志看崩溃在 clr 里,让我能否帮忙定位下,dump 也抓到了,既然dump有了,接下来就上 windbg …...
2020 6.s081——Lab5:Lazy page allocation
再来是千年的千年 不变是眷恋的眷恋 飞越宇宙无极限 我们永不说再见 ——超兽武装 完整代码见:SnowLegend-star/6.s081 at lazy (github.com) Eliminate allocation from sbrk() (easy) 顾名思义,就是去掉sbrk()中调用growproc()的部分。1s完事儿。 Laz…...
华为认证学习笔记:生成树
以太网交换网络中为了进行链路备份,提高网络可靠性,通常会使用冗余链路。但是使用冗余链路会在交换网络上产生环路,引发广播风暴以及MAC地址表不稳定等故障现象,从而导致用户通信质量较差,甚至通信中断。为解决交换网络…...
leetcode 97.交错字符串
思路:LCS 其实也是同一个类型的题目,一般涉及到这种子序列的字符串问题的时候,状态的设置基本上都应该是以...结尾为状态的。这里同样,设置用dp[i][j]为s1,s2字符以i,j结尾能否拼接成s3[ij]。 那么,首先就…...
The Missing Semester ( Shell 工具和脚本 和 Vim)
管道符号 (1)管道符号 | 将前一个命令的输出作为下一个命令的输入 例如: 以下为 ./semester输出中提取包含 "Last-Modified" 的行并写入文件 last-modified.txt./semester | grep "Last-Modified" > ~/last-modif…...
【Uniapp微信小程序】自定义水印相机、微信小程序地点打卡相机
效果图 template 下方的image图片自行寻找替换! <template><view><camerav-if"!tempImagePath && cameraHeight ! 0":resolution"high":frame-size"large":device-position"device":flash"f…...
SimPO: Simple Preference Optimization with a Reference-Free Reward
https://github.com/princeton-nlp/SimPO 简单代码 class simpo(paddle.nn.Layer):def __init__(self):super(OrPoLoss, self).__init__()self.loss paddle.nn.CrossEntropyLoss()def forward(self,neg_logit, neg_lab, pos_logit, pos_lab,beta,gamma):neg_logit paddle.n…...
CDH6.3.2安装文档
前置环境: 操作系统: CentOS Linux release 7.7 java JDK : 1.8.0_231 1、准备工作 准备以下安装包: Cloudera Manager: cloudera-manager-agent-6.3.1-1466458.el7.x86_64.rpm cloudera-manager-daemons-6.3.1-1466458.el…...
Java实战入门:深入解析Java中的 `Arrays.sort()` 方法
文章目录 一、方法定义参数说明返回值 二、使用场景三、实现原理四、示例代码示例一:对整型数组排序示例二:对字符串数组排序示例三:对自定义对象数组排序 五、注意事项六、总结 在Java编程中,Arrays.sort() 方法是一个非常常用的…...
JavaScript的垃圾回收机制
No.内容链接1Openlayers 【入门教程】 - 【源代码示例300】 2Leaflet 【入门教程】 - 【源代码图文示例 150】 3Cesium 【入门教程】 - 【源代码图文示例200】 4MapboxGL【入门教程】 - 【源代码图文示例150】 5前端就业宝典 【面试题详细答案 1000】 文章目录 一、垃圾…...
小程序使用Canvas设置文字竖向排列
在需要使用的js页面引入js文件,传入对应参数即可 /** * 文本竖向排列 */ function drawTextVertical(context, text, x, y) {var arrText text.split();var arrWidth arrText.map(function (letter) {return 26; // 字体间距,需要自定义可以自己加参数,根据传入参数进行…...
GPT-4o:重塑人机交互的未来
一个愿意伫立在巨人肩膀上的农民...... 一、推出 在人工智能(AI)领域,自然语言处理(NLP)技术一直被视为连接人类与机器的桥梁。近年来,随着深度学习技术的快速发展,NLP领域迎来了前所未有的变革…...
大语言模型拆解——Tokenizer
1. 认识Tokenizer 1.1 为什么要有tokenizer? 计算机是无法理解人类语言的,它只会进行0和1的二进制计算。但是呢,大语言模型就是通过二进制计算,让你感觉计算机理解了人类语言。 举个例子:单1,双2&#x…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
负载均衡器》》LVS、Nginx、HAproxy 区别
虚拟主机 先4,后7...
