C++ vector的基本使用

news2024/9/22 11:35:58

目录

 1. vector的定义

 2. 迭代器iterator的使用

3. vector空间增长问题

(1). size与capacity

(2). empty与resize与reserve

4. vector的增删查改

(1) . push_back和pop_back

(2). find与insert与erase 

 (3). swap与operator[]

 5. vector迭代器失效问题

(1). 改变空间

(2). 删除操作导致的失效


std::vector 是C++标准模板库(STL)中的一个非常重要的容器类,它提供了一种动态数组的功能。能够存储相同类型的元素序列,并且可以自动管理存储空间的大小,以适应序列大小变化,处理元素集合的时候很灵活

 1. vector的定义

构造函数声明接口说明
vector();无参构造
vector( size_t n, const value_type& val = value_type());构造并初始化n个val
vector(const vector& x);拷贝构造
vector(InputIterator first, InputIterator last);使用迭代器进行初始化构造

 代码如下

#include<iostream>
#include<vector>
//using namespace std;
using std::vector;
using namespace std;
int main()
{
	vector<int> v1;
	for (size_t i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << "  ";
	}
	cout << endl;
	vector<int> v2(10);
	vector<int> v3(10, 6);
	for (size_t i = 0; i < v2.size(); i++)
	{
		cout << v2[i] << "," << v3[i] << "    ";
	}
	cout << endl;
	vector<int> v4(v2);
	for (size_t i = 0; i < v4.size(); i++)
	{
		cout << v4[i] << "  ";
	}
	cout << endl;

	vector<int> v5(v3.begin(), v3.begin() + 2);
	for (size_t i = 0; i < v5.size(); i++)
	{
		cout << v5[i] << "  ";
	}
	cout << endl;
}

其中v1是无参默认构造, v2是利用了缺省值全初始化为0,v3是初始化n个 6,v4是用v2进行拷贝构造,v5则是利用迭代器进行构造

输出结果如下

 2. 迭代器iterator的使用

iterator的使用接口说明
begin+end获取第一个位置数据的iterator/const_iterator,获取最后一个数据的下一个位置的iterator/const_iterator
rbegin+rend获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的reverse_iterator 

如下图所示

 使用代码如下

#include<iostream>
#include<vector>
//using namespace std;
using namespace std;
int main()
{
	vector<int> v(10,6);
	v.push_back(1);
	//vector<int>::iterator it = v.begin();
	auto it = v.begin();
	while (it != v.end())
	{
		cout << *it << "  ";
		it++;
	}
	cout << endl;
	vector<int>::reverse_iterator iv = v.rbegin();
	while (iv != v.rend())
	{
		cout << *iv << "  ";
		iv++;
	}
	cout << endl;
}

输出结果如下

 使用iterator不可以vector::iterator it = v.begin();  因为vector是一个模板类需要指定其存储元素的类型。直接写没指定vector具体类型,编译器不知道就会报错(比如可能是vector<double>,vector<int>等)。当然也可以直接用auto自动识别。

3. vector空间增长问题

成员函数接口说明
size获取数据个数
capacity获取容量大小
empty判断是否为空
resize改变vector的元素个数(size)
reserve改变vector的容量(capacity)
(1). size与capacity

用以下代码验证vector动态增长

#include<iostream>
#include<vector>
//using namespace std;
using namespace std;
int main()
{
	vector<int> v;
	size_t sz = v.capacity();
	cout << "容量为:" << sz << endl;
	cout << "元素个数:" << v.size() << endl;
	for (int i = 0; i < 100; i++)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "当前容量:" << sz << endl;
			cout << "当前元素个数:" << v.size() << endl;
		}
	}
}

输出结果为下图

 通过上图我们不难发现,在vs中运行每次增长1.5倍,向上取整

而g++下运行每次增长2倍,并不是所有的vector增容都是增长1.5倍或2倍的。具体增长是多少是看具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。

(2). empty与resize与reserve

reserve只负责开辟空间,如果确定要用多少空间,reserve可以缓解vector增容的代价缺陷问题。只影响capacity(),不影响size()

resize在开空间时还会进行初始化,会影响capacity()还会影响size()

 如以下代码

#include<iostream>
#include<vector>
//using namespace std;
using namespace std;
int main()
{
	vector<int> v1;
	size_t sz = v1.capacity();
	cout << "v1容量为:" << sz << endl;
	cout << "v1元素个数:" << v1.size() << endl;
	if(v1.empty())
	{
		v1.reserve(100);
	}
	for (int i = 0; i < 100; i++)
	{
		v1.push_back(i);
		if (sz != v1.capacity())
		{
			sz = v1.capacity();
			cout << "v1当前容量:" << sz << endl;
			cout << "v1当前元素个数:" << v1.size() << endl;
		}
	}
	vector<int> v2;
	cout << "v2容量为:" << v2.capacity() << endl;
	cout << "v2元素个数:" << v2.size() << endl;
	v2.resize(10);
	cout << "v2当前容量为:" << v2.capacity() << endl;
	cout << "v2当前元素个数为:" << v2.size() << endl;
	for (int i = 0; i < v2.size(); i++)
	{
		cout << v2[i] << "  ";
	}
	cout << endl;
	vector<int> v3;
	cout << "v3容量为:" << v3.capacity() << endl;
	cout << "v3元素个数:" << v3.size() << endl;
	v3.resize(10, 3);
	cout << "v3当前容量为:" << v3.capacity() << endl;
	cout << "v3当前元素个数为:" << v3.size() << endl;
	for (int i = 0; i < v3.size(); i++)
	{
		cout << v3[i] << "  ";
	}
	cout << endl;
}

输出结果为下图所示

 可以验证我们以上说法

4. vector的增删查改

vector的元素操作接口说明
push_back尾插
pop_back尾删
find查找(算法模块实现,不是vector成员接口)
insert在position(指定坐标)之前插入val
erase删除position(指定坐标)位置的数据
swap交换两个vector的数据空间
operator[]重载运算符,使其能像数组一样访问
(1) . push_back和pop_back

使用代码如下

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(4);
	v1.push_back(6);
	vector<int>::iterator iv1 = v1.begin();
	while (iv1!=v1.end())
	{
		cout << *iv1 << "   ";
		iv1++;
	}
	cout << endl;

	v1.pop_back();
	iv1 = v1.begin();
	while (iv1 != v1.end())
	{
		cout << *iv1 << "   ";
		iv1++;
	}
	cout << endl;

}

 输出结果为

(2). find与insert与erase 

代码如下

#include<iostream>
#include<vector>
//#include<algorithm>
//using namespace std;
using namespace std;
int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(4);
	v1.push_back(6);
	vector<int>::iterator pos1 = find(v1.begin(), v1.end(), 4);
	cout << *pos1 << endl;
	v1.insert(pos1, 10);
	vector<int>::iterator iv = v1.begin();
	while (iv != v1.end())
	{
		cout << *iv << "  ";
		iv++;
	}
	cout << endl;

	vector<int>::iterator pos2 = find(v1.begin(), v1.end(), 6);
	v1.erase(pos2);
	iv = v1.begin();
	while (iv != v1.end())
	{
		cout << *iv << "  ";
		iv++;
	}
	cout << endl;
}

输出结果为

 (3). swap与operator[]

基本使用代码为

#include<iostream>
#include<vector>
//#include<algorithm>
using namespace std;
int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(4);
	v1.push_back(6);
	vector<int> v2;
	v2.push_back(5);
	v2.push_back(8);
	v2.push_back(2);
	v2.push_back(1);

	v2.swap(v1);

	for (size_t i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << "   ";
	}
	cout << endl;

	for (size_t i = 0; i < v2.size(); i++)
	{
		cout << v2[i] << "   ";
	}
	cout << endl;
}

输出结果如下

 5. vector迭代器失效问题

迭代器的主要作用就是能让算法不用关心底层数据结构,其底层实际就是一个指针或者是对指针进行了封装 例如vector的迭代器就是原生态指针T*

 迭代器失效实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间会造成程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)

(1). 改变空间

会引起底层空间改变的操作都可能使迭代器失效 

比如resize、reserve、insert、assign、push_back等。

#include<iostream>
#include<vector>
//#include<algorithm>
using namespace std;
int main()
{
	vector<int> v1{ 1,2,3,4,5,6 };
	vector<int>::iterator iv1 = v1.begin();
	//将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容
	v1.resize(100,8);
	while (iv1 != v1.end())
	{
		cout << *iv1 << "  ";
		iv1++;
	}
	cout << endl;

	vector<int>v2{ 2,5,6,8,9 };
	vector<int>::iterator iv2 = v2.begin();
	//reserve的作用就是改变扩容大小但不改变有效元素个数
	v2.reserve(100);
	while (iv2 != v2.end())
	{
		cout << *iv2 << "  ";
		iv2++;
	}
	cout << endl;

	vector<int>v3;
	vector<int>::iterator iv3 = v3.begin();
	//插入元素期间,可能会引起扩容,而导致原空间被释放
	v3.insert(v3.begin(), 0);
	v3.push_back(1);
	while (iv3 != v3.end())
	{
		cout << *iv3 << "  ";
		iv3++;
	}
	cout << endl;

	vector<int>v4;
	vector<int>::iterator iv4 = v4.begin();
	v4.assign(10, 4);

	while (iv4 != v4.end())
	{
		cout << *iv4 << "  ";
		iv4++;
	}
	cout << endl;
}

以上所有迭代器全都失效

出错原因如下

以上操作,都有可能导致vector扩容,也就是说vector的旧空间被释放掉,而在打印的时候,iv1,iv2...使用的还是之前的旧空间,对这些迭代器操作时,实际操作的是一块已经被释放的空间,而引起代码运行时崩溃

 解决方式:在以上影响底层空间的操作完成之后,若想通过迭代器操作vector中的元素,只需给it重新赋值即可

(2). 删除操作导致的失效
#include<iostream>
#include<vector>
//#include<algorithm>
using namespace std;
int main()
{
	vector<int> v1{ 1,2,3,4,5,6 };
	vector<int>::iterator pos = find(v1.begin(), v1.end(), 5);

	v1.erase(pos);
	cout << *pos << endl;

}

erase删除pos位置元素,pos位置之后的元素会往前移,不会导致底层空间改变,理论上迭代器不会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end()的位置,而end()位置是没有元素的,此时pos就失效了因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了

(3). Linux下的检测

Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端

1. 扩容后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了

2. erase删除任意位置代码后,Linux下迭代器并没有失效,因为空间还是原来的空间,后续元素往前搬移了,旧迭代器位置还是有效的

3. erase删除的迭代器若是最后一个元素,此时旧迭代器是无效的

 SGL STL中,迭代器失效后,代码不一定会崩溃,但是运行结果肯定不对,

如果迭代器不再begin()和end()范围内,肯定会崩溃的。

另外

与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效


这篇文章到这里就结束啦~喜欢可以点一下赞

(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤

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

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

相关文章

爱玛电动车今年多次抽查不合格:营收增速放缓承压,拟50亿扩产能

《港湾商业观察》廖紫雯 7月26日&#xff0c;市场监管总局发布《2024年上半年电动自行车产品质量国家监督专项抽查结果情况通报》&#xff0c;爱玛电动车五次上榜。 除却一直以来被多次诟病的电动车产品质量问题外&#xff0c;业绩层面上&#xff0c;近两年数据来看&#xff…

从格斗项目的着装和格斗术,理解巴黎奥运会上的拳击、跆拳道、柔道、摔跤之间到底有什么区别?

文章目录 引言I 柔道着装格斗术II 摔跤装备“摔跤耳”格斗术:古典式摔跤和自由式摔跤III 跆拳道装备格斗术等级段位制(“十级九段制”)IV 拳击装备格斗术拳击手小结引言 8月1日巴黎,柔道女子-78公斤级比赛结束,意大利贝兰迪夺得金牌,以色列拉尼尔摘得银牌,中国选手马振昭和…

SAM-Med2D 大模型学习笔记(续):训练自己数据集

1、前言、数据集介绍 SAM-Med2D大模型介绍参考上文&#xff1a;第三章&#xff1a;SAM-Med2D大模型复现-CSDN博客 本文将使用SAM-Med2D大模型训练自己的数据集 关于SAM-Med2D大模型官方demo数据集的介绍上文已经介绍过&#xff0c;这里简单回顾下 其中data_demo为数据集的目…

你的工作环境,选对劳保鞋了吗?守护安全,从脚下开始!

在众多的工作场所中&#xff0c;我们穿梭于不同的工作环境&#xff0c;从繁忙的工厂车间到复杂的建筑工地&#xff0c;再到需要精细操作的实验室……每一步都承载着对安全的期许和对效率的追求。但你是否意识到&#xff0c;脚下那双不起眼的劳保鞋&#xff0c;其实是守护你安全…

洞见优维「全面可观测」:从85%的AI项目败率说起

一直以来&#xff0c;优维都坚信AI有潜力改变运维行业并促进创新&#xff0c;这是我们的A面。但从行业和客户那里&#xff0c;我们所看到的B面也不容忽视。 自从去年底发布优维全面可观测以来&#xff08;点击回顾&#xff09;&#xff0c;我们的团队在服务客户的进程中常常感…

国内下载gradle慢,下载gradle超时问题解决【笔记】

下载gradle超时、慢 修改 找到项目中的gradle-wrapper.properties文件 修改 替换默认下载链接地址 distributionUrlhttps\://services.gradle.org/distributions替换为腾讯或阿里的链接地址 厂商链接阿里https://mirrors.aliyun.com/macports/distfiles/gradle腾讯https://…

vue请求springboot接口下载zip文件

说明 其实只需要按照普通文件流下载即可&#xff0c;以下是一个例子&#xff0c;仅供参考。 springboot接口 RestController RequestMapping("/api/files") public class FileController {GetMapping("/download")public ResponseEntity<Resource>…

C++ 多态三

1.多态的概念 多态的前提的是继承。当不同的对象去完成同一种行为时会产生不同的结果就是多态的通俗意义。 例如学生、成人两个对象去完成买票这个行为&#xff0c;那么学生的结果是获得半价&#xff0c;而成人获得的结果的是全价。 2.多态的定义及实现 2.1构成多态的两个硬…

自闭症学校排名前十,揭秘顶级干预学校

在当今社会&#xff0c;自闭症儿童的数量不断上升&#xff0c;众多家庭都在全力以赴地为孩子寻找适宜的自闭症学校。当面临这一重要抉择时&#xff0c;家长们常常首先想到的便是查看自闭症学校排名前十的榜单。然而&#xff0c;网络上此类排名繁多&#xff0c;其真实性与可靠性…

国产光耦的工作原理、优势以及应用介绍

国产光耦作为一种关键的电子元件&#xff0c;因其卓越的光隔离特性&#xff0c;被广泛应用于电气隔离和信号隔离领域。其可靠的性能使其在电源管理、数据通信和音频处理等领域发挥重要作用。 国产光耦是由发光二极管&#xff08;LED&#xff09;和光敏器件&#xff08;如光敏晶…

查理三世的假期并不理想 对泰勒·斯威夫特主题舞会引发的骚乱未采取其他行动遭各方批评

当查理三世国王在苏格兰巴尔莫勒尔堡享受一年一度的夏日假期时&#xff0c;英国其他地区却在应对由 7 月 29 日泰勒斯威夫特主题舞会上持刀袭击而引发的骚乱。王室成员在宫殿高墙内休息&#xff0c;而暴力事件却不断增多&#xff0c;这种对比让许多原本忠实的粉丝感到不安。 由…

C# 在Word中插入或删除分节符

在Word中&#xff0c;分节符是一种强大的工具&#xff0c;用于将文档分成不同的部分&#xff0c;每个部分可以有独立的页面设置&#xff0c;如页边距、纸张方向、页眉和页脚等。正确使用分节符可以极大地提升文档的组织性和专业性&#xff0c;特别是在长文档中&#xff0c;需要…

BCrypt加密算法的使用及原理

系列文章目录 1.SpringBoot整合RabbitMQ并实现消息发送与接收 2. 解析JSON格式参数 & 修改对象的key 3. VUE整合Echarts实现简单的数据可视化 4. List&#xff1c;HashMap&#xff1c;String,String&#xff1e;&#xff1e;实现自定义字符串排序&#xff08;key排序、Val…

69、zabbix自动、代理、snmp监控

一、zabbix 1.1、自动发现 [roottest1 ~]# systemctl stop firewalld [roottest1 ~]# setenforce 0 [roottest3 ~]# vim /etc/hosts 192.168.168.21 test1 192.168.168.23 test3 [roottest1 ~]# vim /etc/hosts 192.168.168.21 test1 192.168.168.23 test3 ------------…

AI智能名片B2B2C商城系统:优化三度空间渠道布局与避免渠道冲突的新策略

摘要&#xff1a;在数字化浪潮的推动下&#xff0c;品牌商面临着前所未有的市场挑战与机遇。为了应对这些挑战并抓住机遇&#xff0c;品牌商需要构建并优化一个高效、协同的三度空间&#xff08;线下实体店、线上电商平台、数字营销渠道&#xff09;渠道布局。本文深入探讨了AI…

【多线程-从零开始-玖】内核态,用户态,线程池的参数、使用方法详解

文章目录 1. 为什么会有线程池2. 内核态和用户态2.1 场景构造 3. 标准库的线程池3.1 构造方法的参数3.1.1 核心线程数和最大线程数3.1.2 非核心线程允许摸鱼的最大时间3.1.3 工作队列&#xff08;阻塞队列&#xff09;3.1.4 线程工厂工厂设计模式 3.1.5 拒绝策略四种拒绝策略 3…

极投影ax.contourf

我想用极投影画个类似下面这样的效果图&#xff0c;首先底图是一个这样的&#xff0c;然后再有需要的地方做标记&#xff0c;比如斜线和渔网状的东西。 但是我怎么尝试都是得到了一个下面这样的图这样肯定有问题 我调整为画轮廓线之后变成下面这样的图&#xff0c;我猜想应该是…

Python酷库之旅-第三方库Pandas(073)

目录 一、用法精讲 296、pandas.Series.dt.as_unit方法 296-1、语法 296-2、参数 296-3、功能 296-4、返回值 296-5、说明 296-6、用法 296-6-1、数据准备 296-6-2、代码示例 296-6-3、结果输出 297、pandas.Series.dt.days属性 297-1、语法 297-2、参数 297-3、…

Ansys Mechanical|解决温度场-电场耦合问题

一.多物理场耦合分析的必要性 你是否曾经碰到过你的模型受到两个或者更多物理因素影响的情况吗&#xff1f;这些物理因素不仅会相互影响&#xff0c;还会影响计算结果。 这时多物理场分析就有用了。在解决多物理场影响的工程问题时&#xff0c;多物理场耦合分析是必要的。 举…

IO进程----标准IO

目录 IO进程 标准IO 1. 概念&#xff1a; 2. 特点&#xff1a; 3. 缓存区 3.1. 行缓存&#xff1a;和终端操作相关 刷新缓存的条件&#xff1a; 1) 程序正常退出 2) \n刷新 3) 缓存区满刷新 4) 强制刷新 fflush 3.2. 全缓存&#xff1a;和文件操作相关 3.…