STL中 vector常见函数用法和迭代器失效的解决方案【C++】

news2024/9/23 11:24:42

文章目录

  • size && capacity
  • reserve
  • resize
  • empty
  • 迭代器
    • begin和end
  • push_back &&pop_back
  • insert && erase
  • find
  • swap
  • [ ]
  • 范围for遍历vector
  • 迭代器失效问题

size && capacity

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v(10, 2);
	cout << v.size() << endl; //获取当前容器中的有效元素个数
	cout << v.capacity() << endl; //获取当前容器的最大容量
	return 0;
}

reserve

通过reserse函数改变容器的capactiy

1、当所给值大于容器当前的capacity时,将capacity扩大到该值。
2、当所给值小于容器当前的capacity时,什么也不做。

resize

resize函数改变容器中的有效元素个数 ,也就是size

1、当所给值大于容器当前的size时,将size扩大到该值,扩大的元素为第二个所给值,若未给出,则默认为0。
 2、当所给值小于容器当前的size时,将size缩小到该值。

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v(10, 2);
	cout << v.size() << endl; //10
	cout << v.capacity() << endl; //10
	v.reserve(20); //改变容器的capacity为20,size不变
	cout << v.size() << endl; //10
	cout << v.capacity() << endl; //20
	v.resize(15); //改变容器的size为15
	cout << v.size() << endl; //15
	cout << v.capacity() << endl; //20
	return 0;
}

empty

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v(10, 2);
	cout << v.empty() << endl;
	return 0;
}

迭代器

begin和end

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v(10, 2);
	//正向迭代器遍历容器
	vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	return 0;
}

在这里插入图片描述
反向迭代器遍历容器:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v(10, 2);
	//反向迭代器遍历容器
	vector<int>::reverse_iterator rit = v.rbegin();
	while (rit != v.rend())
	{
		cout << *rit << " ";
		rit++;
	}
	cout << endl;
	return 0;
}

push_back &&pop_back

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v;
	v.push_back(1); 
	v.push_back(2);
	v.push_back(3); 
	v.push_back(4);

	v.pop_back();
	v.pop_back(); 
	v.pop_back(); 
	v.pop_back(); 
	return 0;
}

insert && erase

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.insert(v.begin(), 0); //在容器开头插入0
	
	v.insert(v.begin(), 5, -1); //在容器开头插入5个-1

	v.erase(v.begin()); //删除容器中的第一个元素

	v.erase(v.begin(), v.begin() + 5); //删除在该迭代器区间内的元素(左闭右开)
	
	return 0;
}

find

find函数是在算法模块(algorithm)当中实现的,不是vector的成员函数

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	
	vector<int>::iterator pos = find(v.begin(), v.end(), 2); //左闭右开
	//auto pos =find(v.begin()  , v.end() , 2) ;
	v.insert(pos, 10); //在2的位置插入10
    //左闭右开
	pos = find(v.begin(), v.end(), 3); //获取值为3的元素的迭代器
	
	v.erase(pos); //删除3

	return 0;
}

swap

通过swap函数可以交换两个容器的数据空间,实现两个容器的交换。

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v1(10, 1);
	vector<int> v2(10, 2);

	v1.swap(v2); //交换v1,v2的数据空间

	return 0;
}

[ ]

vector当中实现了 [ ] 操作符的重载

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v(10, 1);
	//使用“下标+[]”的方式遍历容器
	for (size_t i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;
	return 0;
}

范围for遍历vector

用范围for对vector容器进行遍历。(支持迭代器就支持范围for,在编译时编译器会自动将范围for替换为迭代器的形式)

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v(10, 1);
	//范围for
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

迭代器失效问题

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。

一、

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	//v: 1 2 3 4 5
	vector<int>::iterator pos = find(v.begin(), v.end(), 2); //获取值为2的元素的迭代器
	//auto pos =find(v.begin(),v.end() ,2);
	v.insert(pos, 10); //在值为2的元素的位置插入10
	//v: 1 10 2 3 4 5
	v.erase(pos); //删除元素2  error(迭代器失效)
	//v: 1 2 3 4 5
	return 0;
}

在该代码中,我们本意是使用元素2的迭代器在原序列中2的位置插入一个10,然后将2删除,但我们实际上获取的是指向2的指针,当我们在2的位置插入10后,该指针就指向了10,所以我们之后删除的实际上是10,而不是2

解决方法:迭代器失效解决办法:在使用前,对迭代器重新赋值即可

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	//v: 1 2 3 4 5
	vector<int>::iterator pos = find(v.begin(), v.end(), 2); //获取值为2的元素的迭代器
	//auto pos =find(v.begin(),v.end() ,2);
	v.insert(pos, 10); //在值为2的元素的位置插入10
	//v: 1 10 2 3 4 5
	pos = find(v.begin(), v.end(), 2); //重新获取值为2的元素的迭代器,(解决迭代器失效,重新赋值即可)
	v.erase(pos); //删除元素2
	//v: 1 10 3 4 5
	return 0;
}

二、

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v;
	v1.push_back(1);
    v1.push_back(2);
    v1.push_back(2);
    v1.push_back(3);
    v1.push_back(4);
    v1.push_back(5);
    v1.push_back(6);
	vector<int>::iterator it = v.begin();
	//auto it = v.begin();
	while (it != v.end())
	{
		if (*it % 2 == 0) //删除容器当中的全部偶数
		{
			v.erase(it);
		}
		it++;
	}
	return 0;
}

在这里插入图片描述

解决方案:我们可以接收erase函数的返回值(erase函数返回删除元素的后一个元素的新位置),并且控制代码的逻辑:当元素被删除后继续判断该位置的元素(因为该位置的元素已经更新,需要再次判断)。

下面是测试vector代码

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
void test_vector1()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	for (size_t i = 0; i < v.size(); ++i)
	{
		cout << v[i];
	}
	cout << endl;
	//迭代器访问 
	vector<int> ::iterator it = v.begin();
	//auto it = v.begin();
	while (it != v.end())
	{
		cout << *it;
		it++;
	}
	cout << endl;
	//范围for 
	for (auto e : v)
	{
		cout << e;
	}
	
}
void test_vector2()
{
	
	vector<string> v;
	//第一种方式
	string name1("zhangsan");
		v.push_back(name1);
	
	//第二种方式
		//匿名对象
		v.push_back(string("zhangsan"));
	
	//第三种方式(推荐)
		v.push_back("zhangsan");
	
}
void test_vector3()
{
	vector<int> v1(10, 1);
	vector<string> v2(10,"***");
	for (auto e : v1)
	{
		cout << e;
	}
	cout << endl;
	for (auto e : v2)
	{
		cout << e;
	}
	cout << endl;
	//自己类型的迭代器
	vector<int> v3(v1.begin(), v1.end());
	for (auto e : v3)
	{
		cout << e;
	}
	cout << endl;
	string str("hello world");
	vector<char> v4 (str.begin(), str.end());
	for (auto e : v4)
	{
		cout << e;
	}
	cout << endl;

	int a[] = { 16,2,77,29 };
	vector<int> v5(a, a + 4);
	for (auto e : v5)
	{
		cout << e<<" ";
	}
	cout << endl;
	//升序  less  < 
	//sort(v5.begin(), v5.end());
	//降序   
	/*sort(v5.rbegin(), v5.rend());*/

	for (auto e : v5)
	{
		cout << e << " ";
	}
	cout << endl;
	//降序 greater > 
	/*greater <int> gt;*/
	//sort(v5.begin(), v5.end(),gt);
	sort(v5.begin(), v5.end(), greater<int>() ); //匿名对象

	for (auto e : v5)
	{
		cout << e << " ";
	}
	cout << endl;
}
void test_vector4()
{
	vector<int>  v1;
	cout << v1.max_size() << endl;
	v1.resize(10);
	//这里使用v1.reserve(10)是错的   []重载的实现里面有assert(pos <_size ) 但是此时_size是0;
	for (size_t i = 0; i < 10; i++)
	{
		v1[i] = i;
	}
	for (auto e : v1)
	{
		cout << e<<" ";
	}
	cout << endl;

	vector <int> v2;
	v2.reserve(10);
	for (size_t i = 0; i < 10; ++i)
	{
		v2.push_back(i);
	}
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;
}
void test_vector5()
{
	int a[] = { 16,2,77,29,3,33,43,3,2,3,3,2 };
	vector<int> v1(a,  a+sizeof(a)/sizeof(int) );
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	 头删
	//v1.erase(v1.begin());
	//for (auto e : v1)
	//{
	//	cout << e << " ";
	//}
	//cout << endl;
	 头插 
	//v1.insert(v1.begin(),16);
	//for (auto e : v1)
	//{
	//	cout << e << " ";
	//}
	//cout << endl;
	// 删除第3个数据
	//v1.erase(v1.begin() + 2);
	//for (auto e : v1)
	//{
	//	cout << e << " ";
	//}
	//cout << endl;
	

	// 删除3,但是不知道3在哪个位置,怎么办?
	//使用迭代器
	vector<int>::iterator   pos =  find(v1.begin(), v1.end(), 3);
	//auto pos = find(v1.begin(), v1.end(), 3);
	// 通过查询文档发现, find函数没有找到会return last
	if (pos != v1.end( ))//find找到了3的位置 
	{
		v1.erase(pos);
	}

	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	// 删除所有的3 -- 涉及迭代器失效!后面解决

	pos = find(v1.begin(), v1.end(), 3);

	while (pos != v1.end())//pos不能越界
		//删除第一个找到的3,然后继续找3 ,删除一个3,更新一次pos 
	{
		v1.erase(pos);//删除第一个找到的3
		pos = find(v1.begin(), v1.end(), 3);//删除一个3,更新一次pos 
	}
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	/*v1.assign(10, 1);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;*/
}
void test_vector6()
{
	string str("hello world");
	sort(str.begin(), str.end());
	cout << str << endl;
	int a[] = { 16,2,77,29 };
	sort(a ,a+4);
	for (auto e : a)
	{
		cout << e << " ";
	}
}
int main()
{
	//test_vector1();
	//test_vector2();
	//test_vector3();
	//test_vector4();
	test_vector5();
	//test_vector6();

	return 0;
}

如果你觉得这篇文章对你有帮助,不妨动动手指给点赞收藏加转发,给鄃鳕一个大大的关注你们的每一次支持都将转化为我前进的动力!!!

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

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

相关文章

一文搞懂如何在群晖NAS中使用cpolar实现【内网穿透】

文章目录 1.1前言2.如何在群晖nas中使用cpolar内网穿透2.1第一步——进入套件中心2.2第二步——管理cpolar套件2.3第三步——建立专属的数据隧道2.4 第四步——查看本地数据隧道状态是否激活 3.结语 1.1前言 今天&#xff0c;我们来为大家介绍&#xff0c;如何在群晖系统中&am…

设计模式-命令模式在Java中的使用示例-桌面程序自定义功能键

场景 欲开发一个桌面版应用程序&#xff0c;该应用程序为用户提供了一系列自定义功能键&#xff0c;用户可以通过这些功能键来实现一些快捷操作。 用户可以将功能键和相应功能绑定在一起&#xff0c;还可以根据需要来修改功能键的设置&#xff0c;而且系统在未来可能还会增加…

做外贸工厂跳过我联系了客户

在我十多年外贸创业历程里&#xff0c;遇过不少想跳过我直接和客户联系的供应商。 譬如给客户发邮件&#xff0c;悄咪咪将我从抄送里删掉。又或者偷偷将名片塞在货柜里&#xff0c;期望客户一开箱就能看到。 然而这么多年过去&#xff0c;一次让他们得逞的机会都没有。每一次…

C++多线程编程(第三章 案例1,使用互斥锁+ list模拟线程通信)

主线程和子线程进行list通信&#xff0c;要用到互斥锁&#xff0c;避免同时操作 1、封装线程基类XThread控制线程启动和停止&#xff1b; 2、模拟消息服务器线程&#xff0c;接收字符串消息&#xff0c;并模拟处理&#xff1b; 3、通过Unique_lock和mutex互斥方位list 消息队列…

【力扣每日一题】2023.7.28 并行课程3

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们课程表以及每门课需要学习的时间&#xff0c;我们可以同时学任意数量的课程&#xff0c;但是学习的条件是先修课程都已经学完了…

【雕爷学编程】MicroPython动手做(02)——尝试搭建K210开发板的IDE环境6

#尝试搭建K210的Micropython开发环境&#xff08;Win10&#xff09; #实验程序之六&#xff1a;测试Microphone阵列算法 #尝试搭建K210的Micropython开发环境&#xff08;Win10&#xff09; #实验程序之六&#xff1a;测试Microphone阵列算法from Maix import MIC_ARRAY as mi…

MySQL运维:从全备sql文件中提取指定表的数据并恢复

目录 一、运行环境 二、需求说明 三、思路分析 五、具体方案 六、恢复表数据 一、运行环境 系统&#xff1a;CentOS7.3 数据库&#xff1a;MySQL 8.0.21 二、需求说明 线上有个表的数据被误操作了很多&#xff0c;无法通过bin-log进行具体的恢复。所以当前我们需要从全…

Spring Boot 应用程序生命周期扩展点妙用

文章目录 前言1. 应用程序生命周期扩展点2. 使用场景示例2.1 SpringApplicationRunListener2.2 ApplicationEnvironmentPreparedEvent2.3 ApplicationPreparedEvent2.4 ApplicationStartedEvent2.5 ApplicationReadyEvent2.6 ApplicationFailedEvent2.7 ApplicationRunner 3. 参…

产品能力|AIRIOT可视化组态引擎如何应用于物联业务场景中

在物联网的业务应用场景中&#xff0c;可视化组态是一个必不可少的功能需求。不同的行业场景&#xff0c;都需要将物联设备采集的数据和业务场景状态进行直观的可视化展示&#xff0c;供使用者进行分析或决策。如工艺流程用能监测、3D场景构建、能耗趋势场景报警联动、重点设备…

RAD-NeRF模型

问题1&#xff1a; 添加在以下的参数里添加bin_size0 问题2&#xff1a; 更行GLIBC_2.29_glibc_2_29.so_xihuanyuye的博客-CSDN博客

如何使用Crank给我们的类库做基准测试

背景 当我们写了一个类库提供给别人使用时&#xff0c;我们可能会对它做一些基准测试来测试一下它的性能指标&#xff0c;好比内存分配等。 在 .NET 的世界中&#xff0c;用 BenchmarkDotNet 来做这件事是非常不错的选择&#xff0c;我们只要写少量的代码就可以在本地运行基准…

【小白必看】Python爬取NBA球员数据示例

文章目录 前言导入需要的库和模块设置请求头和请求地址发送HTTP请求并获取响应处理响应结果解析数据将结果保存到文件完整代码详细解析 运行效果结束语 前言 使用 Python 爬取 NBA 球员数据的示例代码。通过发送 HTTP 请求&#xff0c;解析 HTML 页面&#xff0c;然后提取出需要…

imgcat命令行查看图片

背景 昨天在哔哩哔哩上看到了mac控制台工具imgcat 可以实现在控制台查看图片&#xff0c;我觉得太酷炫了&#xff01;于是手动的安利一下。 下载工具 curl "https://iterm2.com/utilities/imgcat" > imgcat执行权限 chmod x imgcat第一次使用 ./imgcat ~/img…

RocketMQ发送消息还有这种坑?遇到SYSTEM_BUSY不重试?

这里是weihubeats,觉得文章不错可以关注公众号小奏技术&#xff0c;文章首发。拒绝营销号&#xff0c;拒绝标题党 RocketMQ版本 5.1.0 背景 最近线上的RocketMQ集群遇到了如下问题&#xff0c;业务方的小伙伴反馈问题&#xff0c;说出现了 MQBrokerException&#xff1a;CO…

C++数据结构笔记(10)递归实现二叉树的三序遍历

对于三种遍历方式来说&#xff0c;均为先左后右&#xff01;区别在于根结点的位置顺序 先序遍历&#xff1a;根——左——右 中序遍历&#xff1a;左——根——右 后序遍历&#xff1a;左——右——根 &#xff08;所谓先中后的顺序&#xff0c;是指根结点D先于子树还是后于…

力扣算法练习(四)

1.盛水最多的容器(11) 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;…

Vue 常用指令 v-on 自定义参数和事件修饰符

自定义参数就是可以在触发事件的时候传入自定义的值。 文本框&#xff0c;绑定了一个按钮事件&#xff0c;对应的逻辑是sayhi&#xff0c;现在无论按下什么按钮都会触发这个sayhi。但是实际上不是所有的按钮都会触发&#xff0c;只会限定某一些按钮&#xff0c;最常见的按钮就…

linux下nginx的安装和使用

文章目录 &#x1f4d2;安装nginx1️⃣上传到对应目录2️⃣解压nginx3️⃣检查是否启动成功 &#x1f4d2;使用nginx1️⃣简单的反向代理2️⃣介绍location配置中root和alias的区别 &#x1f4d2;安装nginx 官网下载: https://nginx.org/ 我这里自己下载的是稳定版本 nginx-1.…

手撕顺序表

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大一&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 望小伙伴们点赞&#x1f44d;收藏✨加关注哟&#x1f495;&#x1…

标准IO_文件读写_fgetc,getchar,ungetc,fgets,fputs,fread,fwrite

目录 1.单字符文件读写 1.1 单字符读文件 1.1.1 fgetc函数 1.1.2 getc函数 1.1.3 getchar函数 1.1.4 ungetc函数 1.1.5 单字符读文件综合示例代码 1.2 单字符写文件 1.2.1 fputc函数 1.2.2 putc函数 1.2.3 putchar函数 1.2.4 单字符写文件综合示例代码 2.多字符文…