C++中的vector介绍(常用函数)

目录

  • vector的介绍及使用
    • 1.vector的介绍
    • 2.vector的使用
      • 2.1vector的定义
      • 2.2 vector iterator 的使用
      • 2.3vector 空间增长问题
      • 2.4 vector 增删查改
      • 2.5 vector 迭代器失效问题。(重点)
    • 3.动态二维数组理解
    • 4.模拟实现reserve

vector的介绍及使用

1.vector的介绍

vector的文档介绍
在这里插入图片描述
vector是序列容器,表示可以改变大小的数组。

2.vector的使用

vector学习时一定要学会查看文档:vector的文档介绍,vector在实际中非常的重要,在实际中我们熟悉常见的接口就可以,下面列出了哪些接口是要重点掌握的。

2.1vector的定义

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

在这里插入图片描述

int main()
{
	vector<int> v1;//无参的构造
	vector<int> v2(5, 1);//n个val的构造
	vector<int> v3(v2);//拷贝构造
	vector<int> v4(v2.begin(), v2.end());//迭代器区间构造
	return 0;
}

2.2 vector iterator 的使用

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

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
正向迭代器的遍历打印

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;
}

在这里插入图片描述
使用迭代器进行修改

	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())
	{
		*it += 2;
		cout << *it << " ";
		++it;
	}

在这里插入图片描述
反向迭代器的遍历打印

	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	vector<int>::reverse_iterator rit = v.rbegin();
	while (rit != v.rend())
	{
		cout << *rit << " ";
		++rit;
	}

在这里插入图片描述

2.3vector 空间增长问题

容量空间接口说明
size获取数据个数
capacity获取容量大小
empty判断是否为空
resize(重点)改变vector的size
reserve (重点)改变vector的capacity
vector<int> v;
for (int i = 0; i < 10; i++)
{
	v.push_back(i);
}
v.resize(5);//size = 5
v.resize(8,100);//size = 8
v.resize(10);//size = 10

在这里插入图片描述

在这里插入图片描述

(1)capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是
根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。
(2)reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
(3)resize在开空间的同时还会进行初始化,影响size。
VS的环境下:


// 往vecotr中插入元素时,如果大概已经知道要存放多少个元素
// 可以通过reserve方法提前将容量设置好,避免边插入边扩容效率低
size_t sz;
vector<int> v;
sz = v.capacity();
//v.reserve(100);   // 提前将容量设置好,可以避免一遍插入一遍扩容
cout << "making v grow:\n";
for (int i = 0; i < 100; ++i)
{
	v.push_back(i);
	if (sz != v.capacity())
	{
		sz = v.capacity();
		cout << "capacity changed: " << sz << '\n';
	}
}

在这里插入图片描述

2.4 vector 增删查改

vector增删查改接口说明
push_back(重点)尾插
pop_back (重点)尾删
find查找。(注意这个是算法模块实现,不是vector的成员接口)
insert在position之前插入val
erase删除position位置的数据
swap交换两个vector的数据空间
operator[] (重点)像数组一样访问
    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();

在这里插入图片描述

	vector<int> v{ 1,2,3,4,5 };
	auto pos = find(v.begin(), v.end(),3);
	if (pos != v.end())
	{
		v.insert(pos, 100);
	}

在这里插入图片描述

vector<int> v{ 1,2,3,4,5 };
auto pos = find(v.begin(), v.end(),3);
if (pos != v.end())
{
	//v.insert(pos, 100);
	v.erase(pos);
}

在这里插入图片描述

2.5 vector 迭代器失效问题。(重点)

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

vector<int> v{ 1,2,3,4,5 };
auto it = v.begin();
v.reserve(100);
// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变

//it = v.begin();//重新赋值,就不会报错
while (it != v.end())
{
	cout << *it << " ";
	++it;
}

出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的空间,而引起代码运行时崩溃。
解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新赋值即可
B.指定位置元素的删除操作–erase

vector<int> v{ 1,2,3,4,5 };
vector<int>::iterator it = find(v.begin(), v.end(), 3);
v.erase(it);
//it = v.begin();//重新赋值,就不会报错
//cout << *it << endl;//迭代器失效,此处会导致非法访问

erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理
论上讲迭代器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。
注意:与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效。

3.动态二维数组理解

vector<vector<int>> vv;构造一个vv动态二维数组,vv中总共有n个元素,每个元素都是vector类型的,每行没有包含任何元素

vector<vector<int>> vv;
for (int i = 0; i < 5; i++)
{
	for (int j = 0; j < 5; j++)
	{
		vv[i][j] = i * j;//vv.operator[](i).operator[](j) = i * j;
	}
}

在这里插入图片描述

4.模拟实现reserve

void reserve(size_t n)
{
	if (capacity() < n)
	{
		size_t old_size = size();
		T* tmp = new T[n];
		memcpy(tmp, _start, sizeof(T) * size());
		delete[] _start;
		_start = tmp;
		_finish = tmp + old_size;
		_end_of_storage = tmp + n;
	}

假设模拟实现的vector中的reserve接口中,使用memcpy进行的拷贝,以下代码会发生什么问
题?

vector<string> vs;
vs.push_back("1111");
vs.push_back("2222");
vs.push_back("3333");
vs.push_back("4444");
vs.push_back("5555");//扩容

在这里插入图片描述

  1. memcpy是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中
  2. 如果拷贝的是 自定义类型的元素,memcpy既高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝。
    正确的模拟实现
void reserve(size_t n)
{
	if (capacity() < n)
	{
		size_t old_size = size();
		T* tmp = new T[n];
		for (int i = 0; i < old_size; i++)
		{
			tmp[i] = _start[i];
		}
		delete[] _start;
		_start = tmp;
		_finish = tmp + old_size;
		_end_of_storage = tmp + n;
	}
}

结论:如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是浅拷贝,否则可能会引起内存泄漏甚至程序崩溃。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot的“社区医院管理服务系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“社区医院管理服务系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统首页界面图 用户注册界面图 医生界面…

基于x86_64汇编语言简单教程1: 环境预备与尝试

目录 前言 环境配置 基本硬件与操作系统要求 WSL VSCode基本配置(For Windows) 安装基本的依赖 为您的VSCode安装插件&#xff1a; 学习要求 入门 先试试味道 前言 笔者最近正在梭哈使用NASM汇编器的x86 32位汇编&#xff0c;笔者这里记录一下一个晚上的成果。 环境…

chrome清除https状态

莫名其妙的http跳转到https的url了。 解决办法 浏览器地址栏输入&#xff1a;chrome://net-internals/#hsts 输入你需要删除的域名即可&#xff01;&#xff01;&#xff01;

工业级三防平板在工厂极端环境下保障稳定运行

在现代工业环境中&#xff0c;尤其是在工厂车间&#xff0c;设备和技术的稳定性直接关系到生产效率与产品质量。然而&#xff0c;极端的工作条件常常给电子设备的使用带来了不小的挑战。为此&#xff0c;市场上出现了一种专为工业应用设计大尺寸手持三防平板电脑。这种设备以其…

大数据-172 Elasticsearch 索引操作 与 IK 分词器 自定义停用词 Nginx 服务

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

空开老化损坏更换

如果预算充足&#xff0c;空开电流选择比常用工况多30%最佳&#xff0c;太大也没必要。 设备 空开一般质保一年到三年。 现象 这个空开用了三年多&#xff0c;最近跳闸越来越频繁。 这是相关人员安装的充分落实减负增效&#xff0c;工况和空开最大功率相一致&#xff0c;三年…

java基于SpringBoot+Vue+uniapp微信小程序的自助点餐系统的详细设计和实现(源码+lw+部署文档+讲解等)

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

使用短效IP池的优势是什么?

短效IP池作为代理IP服务中一种独特的资源管理方式&#xff0c;其应用已经在数据采集、市场分析和网络安全等多个领域中展示出强大的功能。尽管“短效”听起来似乎意味着某种限制&#xff0c;然而在某些特定的应用场景下&#xff0c;短效IP池却提供了无可比拟的优势。本文将详细…

Linux:Linux中第一个小程序_进度条

前言&#xff1a; 在日常生活中&#xff0c;我们下载软件&#xff0c;文件&#xff0c;都会都一个进度显示&#xff0c;来告知我们的下载进度&#xff0c;接下来我们可以自己手搓一个进度条&#xff0c;在我们自己写扫雷、贪吃蛇等小游戏时&#xff0c;可以做一个游戏加载进度使…

【Hive】6-Hive函数、运算符使用

Hive函数、运算符使用 Hive内置运算符 概述 整体上&#xff0c;Hive支持的运算符可以分为三大类&#xff1a;关系运算、算术运算、逻辑运算。 官方参考文档&#xff1a;https://cwiki.apache.org/confluence/display/Hive/LanguageManualUDF 也可以使用下述方式查看运算符的…

数控机械制造工厂ERP适用范围有哪些

在当今制造业高速发展的背景下&#xff0c;企业资源计划(ERP)系统已成为提升工厂管理效率、实现生产自动化与信息化的关键工具。特别是对于数控机械制造工厂而言&#xff0c;一个合适的ERP系统能够帮助其优化生产流程、提高产品质量、降低生产成本并增强市场竞争力。 1. 生产计…

Windows上安装Go并配置环境变量(图文步骤)

前言 1. 本文主要讲解的是在windows上安装Go语言的环境和配置环境变量&#xff1b; Go语言版本&#xff1a;1.23.2 Windows版本&#xff1a;win11&#xff08;win10通用&#xff09; 下载Go环境 下载go环境&#xff1a;Go下载官网链接(https://golang.google.cn/dl/) 等待…

Dokcer如何容器部署及常见问题

本文讲解通过Docker部署Jenkins过程及遇到的问题。 通过 Docker 部署 Jenkins 使用 Docker 来部署 Jenkins 是一个快速且高效的方式。以下是使用 Docker 部署 Jenkins 的分步骤指南&#xff1a; 1. 安装 Docker 如果你的系统上还没有安装 Docker&#xff0c;请根据操作系统…

VScode实现服务器免密登录(亲测有效)

目录 1 免密步骤1.1 在本地生成密钥1.2 在vscode中下载Remote-SSH1.3 配置SSH文件1.4 在服务器中添加本地公开密钥1.5 远程免密连接试验 2 后记 1 免密步骤 1.1 在本地生成密钥 window R打开命令面板 ssh-keygen1.2 在vscode中下载Remote-SSH 1.3 配置SSH文件 本地密钥的文…

快速查看平台信息脚本(完善中...)

前言&#xff1a; 在熟悉一个平台时&#xff0c;我们经常要去了解这个平台的一些信息&#xff0c;例如架构、CPU核心情况、线程数、用户、内存、磁盘等信息&#xff0c;所以我将这些命令汇总成脚本~方便查看。后面会持续更新&#xff0c;尽量从兼容以及实用地角度修改脚本.....…

JUC并发编程进阶2:CompletableFuture

1 Future接口理论知识复习 Future接口&#xff08;FutureTask实现类&#xff09;定义了操作异步任务执行一些方法&#xff0c;如获取异步任务的执行结果、取消异步任务的执行、判断任务是否被取消、判断任务执行是否完毕等 举例&#xff1a;比如主线程让一个子线程去执行任务…

基于SpringBoot+Vue+uniapp微信小程序的澡堂预订的微信小程序的详细设计和实现

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

Java项目实战II基于Spring Boot的毕业就业信息管理系统设计与实现(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着高校扩…

Python酷玩之旅_数据分析入门(matplotlib)

导览 前言matplotlib入门1. 简介1.1 Pairwise data1.2 Statistical distributions1.3 Gridded data1.4 Irregularly gridded data1.5 3D and volumetric data 2. 实践2.1 安装2.2 示例 结语系列回顾 前言 翻看日历&#xff0c;今年的日子已划到了2024年10月19日&#xff0c;今天…

【重学 MySQL】七十二、轻松掌握视图的创建与高效查看技巧

【重学 MySQL】七十二、轻松掌握视图的创建与高效查看技巧 创建视图查看视图注意事项 在MySQL数据库中&#xff0c;视图&#xff08;View&#xff09;是一种虚拟表&#xff0c;它基于一个或多个表的数据计算生成结果集&#xff0c;但不存储实际的数据。视图可以简化复杂的查询、…