C++ vector
前言:
vector的部分源码:
(做过删除,留下关键信息)
vector的使用
构造函数:
1 无参构造
vector<int> v1;
2 构造并初始化n个val
vector<int> v2(5,1);
3 拷贝构造
vector<int> v3(v2);
4 使用迭代器进行初始化构造
迭代器可以是任意容器的迭代器
vector<int> v3(v2.begin(), v2.end());
string s("hello");vector<int> v3(s.begin(), s.end());
vector的 iterator 的使用
1 begin+end (顺序)
获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下一个位置的iterator/const_iterator
string s("hello");vector<int> v2(s.begin(),s.end());vector<int>::iterator it = v2.begin();//auto it = v2.begin();while (it != v2.end()){cout << *it << " ";it++;}cout << endl;
有迭代器,就可以使用范围for遍历数组
for (auto e : v2){cout << e << " ";}cout << endl;
const对象使用const迭代器进行遍历打印:
const vector<int> v(5,3);vector<int>::const_iterator it = v.begin();while (it != v.end()){cout << *it << " ";it++;}cout << endl;
2 rbegin+rend(逆序)
获取最后一个数据位置的reverse_iterator/const_reverse_iterator,获取第一个数据前一个位置的
reverse_iterator/const_reverse_iterator
string s("hello");vector<int> v2(s.begin(),s.end());vector<int>::reverse_iterator rit = v2.rbegin();//auto rit = v2.rbegin();while (rit != v2.rend()){cout << *rit << " ";rit++;}cout << endl;
vector的容量空间
size:获取数据个数
capacity:获取容量大小
empty:判断是否为空
1 resize
改变vector的size
reisze(size_t n, const T& data = T())
n<size 删除作用
size<n<capacitty 插入作用
n>capacity 扩容+插入
传参给val,就用传过来的值,若没有传参,则用缺省值:匿名对象(先调用构造完成初始化)拷贝构造val
可完成开空间+初始化
vector<int> v;v.resize(4);
2 reserve
改变vector的capacity
reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题
vector<int> v;//v.reserve(100);size_t sz = v.capacity();for (size_t i = 0; i < 100; i++){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "扩容:" << sz << endl;}}
使用reserve,没有发生扩容
vector<int> v;v.reserve(100);size_t sz = v.capacity();for (size_t i = 0; i < 100; i++){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "扩容:" << sz << endl;}}
如果已经确定vector中要存储元素大概个数,可以提前将空间设置足够,就可以避免边插入边扩容导致效率低下的问题了
vector 增删查改
1 push_back(尾插)
2 pop_back(尾删)
vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";it++;}cout << endl;v.pop_back();v.pop_back();it = v.begin();while (it != v.end()){cout << *it << " ";it++;}cout << endl;
3 find
find不是vector自身提供的方法,是STL提供的算法,是算法模块实现,不是vector的成员接口
4 insert
在指定位置前插入值为val的元素,比如:3之前插入30,如果没有则不插入
5 erase
vector<int> v{ 1,2,3 ,4};// 使用列表方式初始化,C++11新语法vector<int>::iterator pos= find(v.begin(), v.end(), 3);//1. 先使用find查找3所在位置if (pos != v.end()){v.insert(pos, 20);// 2. 在pos位置之前插入30}auto it = v.begin();while (it != v.end()){cout << *it << " ";it++;}cout << endl;pos = find(v.begin(), v.end(), 3);v.erase(pos);it = v.begin();while (it != v.end()){cout << *it << " ";it++;}cout << endl;
insert和erase以后迭代器都失效了,不能在访问,所以以上代码中的迭代器pos在insert以后失效,重新赋值后,才可以使用
vector 迭代器失效问题
迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T*
迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)
迭代器失效解决办法:在使用前,对迭代器重新赋值即可
对于vector可能会导致其迭代器失效的操作有:
1. 会引起其底层空间改变的操作,都有可能使迭代器失效
比如:resize、reserve、insert、assign、push_back等
vector<int> v{ 1,2,3,4,5,6 };auto it = v.begin();v.resize(100, 8);//扩容了,旧空间被释放掉//v.reserve(100)//扩容了//v.insert(v.begin(), 0);//扩容了//v.push_back(0);//扩容了//v.assign(100, 8);//扩容了while (it != v.end())//操作的是已经释放掉的旧空间,程序崩溃{cout << *it << " ";it++;}cout << endl;
程序崩溃原因:以上操作,都有可能会导致vector扩容,一旦扩容,vector底层原理旧空间被释放掉,而在打印时,it使用的是已经释放掉的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的空间,而引起代码运行时崩溃
解决方案:给it重新赋值即可
vector<int> v{ 1,2,3,4,5,6 };auto it = v.begin();v.resize(100, 8);it = v.begin();//重新赋值while (it != v.end()){cout << *it << " ";it++;}cout << endl;
2. 指定位置元素的删除操作--erase
vector<int> v{ 1,2,3,4,5,6 };auto pos = find(v.begin(), v.end(), 5);v.erase(pos); 删除pos位置的数据,导致pos迭代器失效cout << *pos << endl;//非法访问
erase删除pos位置元素后,pos位置之后的元素会全部往前移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了
下面来看实例:
删除vector中所有的偶数
错误代码:
vector<int> v{ 1, 2, 3, 4 };auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)v.erase(it);//erase以后,it迭代器失效++it;//报错}
正确代码:
vector<int> v{ 1, 2, 3, 4 };auto it = v.begin();while (it != v.end()){if (*it % 2 == 0){it = v.erase(it);//it失效,重新赋值,it成为下一个要判断的数据的迭代器}else{it++;}}for (auto e : v){cout << e << " ";}cout << endl;
3 注意
Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端
1. 扩容之后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了
2. erase删除任意位置代码后,linux下迭代器并没有失效,因为空间还是原来的空间,it的位置还是有效的
3 erase删除的迭代器如果是最后一个元素,it已经等于end,失效了,++it导致程序崩溃
4 与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效
vector的遍历
1 operator[]
vector<int> v{ 1,2,3,4 };for (size_t i = 0; i < v.size(); i++){v[i] *= 10;//写cout << v[i]<<" ";//读}

2 迭代器遍历
vector<int> v{ 1,2,3,4 };vector<int>::iterator it = v.begin();//auto it = v.begin();while (it != v.end()){cout << *it << " ";it++;}cout << endl;
3 范围for遍历
for (auto e : v){cout << e << " ";}cout << endl;
相关文章:

C++ vector
前言: vector的部分源码: (做过删除,留下关键信息) vector的使用 构造函数: 1 无参构造 vector<int> v1; 2 构造并初始化n个val vector<int> v2(5,1);3 拷贝构造 vector<int> v3…...
Spring+redis集成redis缓存
1、引入maven依赖 <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.7.0</version></dependency><dependency><groupId>org.springframework.data</groupId><art…...
聊聊springboot的启动事件
序 本文主要研究一下springboot的启动事件 SpringApplicationEvent org/springframework/boot/context/event/SpringApplicationEvent.java public abstract class SpringApplicationEvent extends ApplicationEvent {private final String[] args;public SpringApplicatio…...

jmeter HTTP请求默认值
首先,打开JMeter并创建一个新的测试计划。 右键单击测试计划,选择"添加" > “配置元件” > “HTTP请求默认值”。 在HTTP请求默认值中,您可以设置全局的HTTP请求属性,例如: 服务器地址:…...
CSS选择器-CSS3属性
CSS选择器-CSS3属性 持续更新… 1、CSS3的概念和优势 css3概念:是css的升级版本,新增加了一些模块 css3优点:完全向后兼容,可使用新的选择器和属性,能实现新的设计效果CSS3是CSS技术的升级版本,CSS3语言开发是朝着模块化发展的。以前的规范作为一个模块实在是太庞…...

线性代数的学习和整理8:行列式相关
目录 1 从2元一次方程组求解说起 1.1 直接用方程组消元法求解 1.2 有没有其他方法呢?有:比如2阶行列式方法 1.3 3阶行列式 2 行列式的定义 2.1 矩阵里的方阵 2.2 行列式定义:返回值为标量的一个函数 2.3 行列式的计算公式 2.4 克拉…...

java+springboot+mysql农业园区管理系统
项目介绍: 使用javaspringbootmysql开发的农业园区管理系统,系统包含超级管理员、管理员、用户角色,功能如下: 超级管理员:管理员管理;用户管理;土地管理(租赁)&#x…...

IDEA远程开发
IDEA远程开发 前期准备 IDEA的远程开发是在本地去操昨远程服务器上的代码,所以我们先需要准备一台服务器,在此我使用vmware虚拟出ubuntu-20.04.6的Server版本,以便后面演示。 Ubuntu的Java环境配置 JDK8 sudo apt install openjdk-8-jdkmaven sudo apt instal…...
Redis 工作总结
1.Redis是什么 Redis是互联网技术领域使用最为广泛的存储中间件,它是Remote Dictionary Service的首字母缩写,也就是远程字典服务。 2.Redis的用途? 2.1 计数器 2.2 缓存 2.3 分布式锁 2.4 消息中间件 3.Redis的数据类型 3.1 string&am…...
GO学习之 数据库(Redis)
GO系列 1、GO学习之Hello World 2、GO学习之入门语法 3、GO学习之切片操作 4、GO学习之 Map 操作 5、GO学习之 结构体 操作 6、GO学习之 通道(Channel) 7、GO学习之 多线程(goroutine) 8、GO学习之 函数(Function) 9、GO学习之 接口(Interface) 10、GO学习之 网络通信(Net/Htt…...

谈一谈浏览器与Node.js中的JavaScript事件循环,宏任务与微任务机制
JavaScript中的异步代码 JavaScript是一个单线程非阻塞的脚本语言。这代表代码是执行在一个主线程上面的。但是JavaScript中有很多耗时的异步操作,例如AJAX,setTimeout等等;也有很多事件,例如用户触发的点击事件,鼠标…...
User Java bean的命名规范
Java Bean 是一种用于表示简单的、可重用的组件的规范。它是一个符合特定命名和约定的 Java 类,通常用于封装数据和提供访问方法。以下是关于 Java Bean 命名规范的一些准则: 类名: 类名应该使用驼峰命名法(Camel Case)…...
ajax和fetch的区别
ajax 和 fetch的相同点和区别是什么? 以前我们都用ajax去做请求, 但是原生的ajax不好用,我们会用$.ajax或者axios插件去请求,他们都是ajax的封装 最近出来个fetch是什么? 问到这里的时候,你就已经入坑了&am…...

java+springboot+mysql村务档案管理系统
项目介绍: 使用javaspringbootmysql开发的村务档案管理系统,系统包含超级管理员、工作人员角色,功能如下: 超级管理员:系统用户管理(工作人员管理);公开资料;会议记录&…...

windows查看/删除DNS缓存
一、查看DNS缓存 打开CMD,输入ipconfig/displaydns 二、删除DNS缓存 打开CMD,输入ipconfig/flushdns...

自动化测试之Junit
Junit引入注解参数化单参数多参数方法传参 测试用例执行顺序断言测试套件 Junit引入 Junit来编写和组织自动化测试用例,使用Selenium来实际模拟用户与Web应用程序的交互。也就是使用JUnit的测试功能来管理和运行Selenium测试。常见的做法是,使用JUnit作…...

Spring Boot 整合MyBatis-Plus
😀前言 本篇博文是关于Spring Boot 整合MyBatis-Plus的,希望你能够喜欢😊 🏠个人主页:晨犀主页 🧑个人简介:大家好,我是晨犀,希望我的文章可以帮助到大家,您的…...

CC++ 常用技巧
C 中的C C 是面向过程的是把整个大程序分为一个个的子函数;C 是面向对象的是把整个程序划分为一个个的类。C 是完全兼容C 的,C 是C 的子集,C 是C 的超集。C 又对C 做了很多补充和提升,因此使用C 会比使用纯C 更方便。混用C和C&am…...

【AndroidStudio】屏蔽小米打印
使用小米手机调试时,会一直有notifyQueue load error的打印 在过滤器重添加过滤条件即可 -message:notifyQueue...

Tomcat的安装与介绍
首先我们先了解一下什么是服务器?什么是服务器软件? 什么是服务器?安装了服务器软件的计算机。 什么是服务器软件? 服务器软件是一种运行在服务器操作系统上,用于接收和处理客户端请求,并提供相应服务和资…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...

OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...