C++:vector基础讲解
hello,各位小伙伴,本篇文章跟大家一起学习《C++:vector基础讲解》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 !
如果本篇文章对你有帮助,还请各位点点赞!!!

话不多说,开始进入正题
文章目录
- :maple_leaf:关于vector
- :maple_leaf:vector构造函数
- :leaves:vector() 无参构造(默认构造)
- :leaves:vector(size_type n, const value_type& val = value_type()) 构造并初始化n个val
- :leaves:vector(const vector& x) 拷贝构造
- :leaves:vector (InputIterator first, InputIterator last);使用迭代器进行初始化构造
- :leaves:vector{type n1,type n2,type n3...}
- :maple_leaf:vector iterator 的使用
- :leaves:begin
- :leaves:end
- :maple_leaf:vector关于空间的函数
- :leaves:size
- :leaves:capacity
- :leaves:empty
- :leaves:resize
- :leaves:reserve
- :maple_leaf:vector 增删查改
- :leaves:push_back 尾插
- :leaves:pop_back 尾删
- :leaves:find 查找
- :leaves:insert 插入
- :leaves:erase 删除数据
- :leaves:swap 交换vector的数据空间
- :leaves:operator[] `[]`运算符重载
- :maple_leaf:vector迭代器失效问题
- :leaves: 会引起其底层空间改变的操作,都有可能是迭代器失效
- :leaves:2. 指定位置元素的删除操作--erase
- :leaves:注意:Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端。
- :leaves:与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效
- :leaves:解决办法
🍁关于vector
vector是表示可变大小数组的序列容器。能够用下标访问数组中的元素,相对于普通数组能够动态增长。本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。vector相比于其他容器访问元素会更加高效,但是对于不在末尾在插入数据和删除数据时效率更低。
🍁vector构造函数
🍃vector() 无参构造(默认构造)
vector<int>p;
🍃vector(size_type n, const value_type& val = value_type()) 构造并初始化n个val
vector<int>p1(10,1);
vector<string>p2(10,"abcd");
🍃vector(const vector& x) 拷贝构造
vector<int>p1(10,1);
vector<int>p2(p1);
🍃vector (InputIterator first, InputIterator last);使用迭代器进行初始化构造
string s1("abcde");
vector<char>p1(s1.begin(),s1.end());
vector<int>p2(p1.begin(),p1.end());
🍃vector{type n1,type n2,type n3…}
vector<int>v{1,2,3,4,5};
这种初始化,会生成一个类型为initializer_list的初始化列表,用来初始化v

这种初始化列表template< class T > class initializer_list;
是一种模板
🍁vector iterator 的使用
🍃begin
获取第一个数据位置的iterator/const_iterator
vector<int>p(10,1);
iterator lt = p.begin();
cout<<(*lt)<<endl;
🍃end
获取最后一个数据的下一个位置的iterator/const_iterator
vector<int>p(10,1);
iterator lt = p.end();
🍁vector关于空间的函数
🍃size
获取数据个数
vector<int>p(10,1);
cout<<p.size();
🍃capacity
获取容量大小
vector<int>p(10,1);
cout<<p.capacity();
🍃empty
判断是否为空
vector<int>p1(10,1);
cout<<p1.empty()<<endl;vector<int>p2;
cout<<p2.empty()<<endl;
🍃resize
void resize (size_type n, value_type val = value_type());
改变vector的size,当扩容时n > 扩容前的capacity,也会影响capacity
缩容:
vector<int>p1(10,1);
cout<<p1.size()<<endl;
p1.resize(5)
vector<int>p1;
cout<<p1.size()<<endl;
扩容:
vector<int>p1(10,1);
cout<<p1.size()<<endl;
p1.resize(20,2)
vector<int>p1;
cout<<p1.size()<<endl;
for(auto& e : p1)
{cout<<e<<" ";
}
cout<<endl;
扩容时,可以传第二个参数,用此值来初始化扩容的空间,也可以不传第二个参数,会自动调用构造函数初始化扩容的空间
🍃reserve
改变vector的capacity
vector<int>p1(10,1);
cout<<p1.capacity()<<endl;
p1.reserve(100);
vector<int>p1;
cout<<p1.capacity()<<endl;
有些编译器会缩容,有些不会,一般不建议用reserve来缩容。
reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问
题。
🍁vector 增删查改
🍃push_back 尾插
void push_back (const value_type& val);
vector<char>str(5,'a');
str.push_back('b');
cout << str[str.size() - 1];
cout << endl;
🍃pop_back 尾删
void pop_back();
vector<char>str(5,'a');
str.push_back('c');
cout << str[5] << endl;
cout << str.size() << endl;
str.pop_back();
cout << str.size() << endl;
🍃find 查找
(注意这个是算法模块实现,不是vector的成员接口)
template <class InputIterator, class T>
InputIterator find (InputIterator first, InputIterator last, const T& val);
vector<int>nums(10);
for(int i = 0;i < 10;++i)
{nums[i] = i;
}
🍃insert 插入
在指定位置前插入
(1)iterator insert (iterator position, const value_type& val);插入一个元素
(2)void insert (iterator position, size_type n, const value_type& val);插入n个元素
(3)template< class InputIterator >迭代器模板
void insert (iterator position, InputIterator first, InputIterator last);插入一段区间
可知返回值是迭代器类型,insert返回的是在插入元素的位置
int arr[3] = { 9,9,9 };
vector<int>v(3, 1);v.insert(v.begin(), 1);// 一个元素
for (auto& e : v)
{cout << e << " ";
}
cout << endl;v.insert(v.begin(), 10, 0);// n个元素
for (auto& e : v)
{cout << e << " ";
}
cout << endl;v.insert(v.begin(), arr, arr + 3);// 一段区间
for (auto& e : v)
{cout << e << " ";
}
cout << endl;cout << *lt << endl;
🍃erase 删除数据
删除position位置的数据
iterator erase (iterator position);iterator erase (iterator first, iterator last);
erase也是返回迭代器类型,返回的是删除数据的位置(pos)的后一个位置
int arr[3] = { 3,2,1 };
vector<int>v;
v.insert(v.begin(), arr, arr + 3);
for (auto& e : v)
{cout << e << " ";
}
cout << endl;
vector<int>::iterator lt = v.erase(v.begin());
for (auto& e : v)
{cout << e << " ";
}
cout << endl;
cout << *lt << endl;
🍃swap 交换vector的数据空间

void swap (vector& x);
int arr1[3] = { 3,2,1 };
int arr2[3] = { 1,2,3 };
vector<int>v1;
vector<int>v2;
v1.insert(v1.begin(), arr1, arr1 + 3);
v2.insert(v2.begin(), arr2, arr2 + 3);
for (auto& e : v1)// 交换前
{cout << e << " ";
}
cout << endl;
for (auto& e : v2)
{cout << e << " ";
}
cout << endl;swap(v1, v2);// 交换后
for (auto& e : v1)
{cout << e << " ";
}
cout << endl;
for (auto& e : v2)
{cout << e << " ";
}
cout << endl;
🍃operator[] []运算符重载
reference operator[] (size_type n); 非const修饰
const_reference operator[] (size_type n) const; const修饰
通过下标访问vector的元素,很方便,像数组一样访问
int arr1[3] = { 3,2,1 };
vector<int>v1;
v1.insert(v1.begin(), arr1, arr1 + 3);
cout << v1[0] << " " << v1[1] << " " << v1[2] << endl;
🍁vector迭代器失效问题
迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。
对于vector可能会导致其迭代器失效的操作有:
🍃 会引起其底层空间改变的操作,都有可能是迭代器失效
比如:resize、reserve、insert、assign、push_back 等。
#include <iostream>
using namespace std;
#include <vector>int main()
{vector<int> v{1,2,3,4,5,6};auto it = v.begin();// 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容// v.resize(100, 8);// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变// v.reserve(100);// 插入元素期间,可能会引起扩容,而导致原空间被释放// v.insert(v.begin(), 0);// v.push_back(8);// 给vector重新赋值,可能会引起底层容量改变v.assign(100, 8);/*出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,
而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的
空间,而引起代码运行时崩溃。解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新
赋值即可。*/while(it != v.end()){cout<< *it << " " ;++it;}cout<<endl;return 0;
}
🍃2. 指定位置元素的删除操作–erase
#include <iostream>
using namespace std;
#include <vector>int main()
{int a[] = { 1, 2, 3, 4 };vector<int> v(a, a + sizeof(a) / sizeof(int));// 使用find查找3所在位置的iteratorvector<int>::iterator pos = find(v.begin(), v.end(), 3);// 删除pos位置的数据,导致pos迭代器失效。v.erase(pos);cout << *pos << endl; // 此处会导致非法访问return 0;
}
通常情况下earse删除数据后,pos位置后的元素会向前移动,迭代器不会失效,但如果删除的是最后一个元素,就会发生迭代器失效,因为此时迭代器指向end位置,end位置是没有元素的。
🍃注意:Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端。
// 1. 扩容之后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了
int main()
{vector<int> v{1,2,3,4,5};for(size_t i = 0; i < v.size(); ++i)cout << v[i] << " ";cout << endl;auto it = v.begin();cout << "扩容之前,vector的容量为: " << v.capacity() << endl;// 通过reserve将底层空间设置为100,目的是为了让vector的迭代器失效 v.reserve(100);cout << "扩容之后,vector的容量为: " << v.capacity() << endl;// 经过上述reserve之后,it迭代器肯定会失效,在vs下程序就直接崩溃了,但是linux下不会// 虽然可能运行,但是输出的结果是不对的while(it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}程序输出:
1 2 3 4 5
扩容之前,vector的容量为: 5
扩容之后,vector的容量为: 100
0 2 3 4 5 409 1 2 3 4 5
// 2. erase删除任意位置代码后,linux下迭代器并没有失效
// 因为空间还是原来的空间,后序元素往前搬移了,it的位置还是有效的
#include <vector>
#include <algorithm>int main()
{vector<int> v{1,2,3,4,5};vector<int>::iterator it = find(v.begin(), v.end(), 3);v.erase(it);cout << *it << endl;while(it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}程序可以正常运行,并打印:
4
4 5
// 3: erase删除的迭代器如果是最后一个元素,删除之后it已经超过end
// 此时迭代器是无效的,++it导致程序崩溃
int main()
{vector<int> v{1,2,3,4,5};// vector<int> v{1,2,3,4,5,6};auto it = v.begin();while(it != v.end()){if(*it % 2 == 0)v.erase(it);++it;}for(auto e : v)cout << e << " ";cout << endl;return 0;
}========================================================
// 使用第一组数据时,程序可以运行
[sly@VM-0-3-centos 20220114]$ g++ testVector.cpp -std=c++11
[sly@VM-0-3-centos 20220114]$ ./a.out
1 3 5
=========================================================
// 使用第二组数据时,程序最终会崩溃
[sly@VM-0-3-centos 20220114]$ vim testVector.cpp
[sly@VM-0-3-centos 20220114]$ g++ testVector.cpp -std=c++11
[sly@VM-0-3-centos 20220114]$ ./a.out
Segmentation fault
🍃与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效
string s1("hello");
string::iterator lt = --s1.end();
for (auto& e : s1)
{cout << e << " ";
}
cout << endl;
s1.erase(--s1.end());// erase后,lt迭代器已经失效
for (auto& e : s1)
{cout << e << " ";
}
cout << *lt << endl;// 会运行崩溃
🍃解决办法
迭代器失效解决办法:在使用前,对迭代器重新赋值即可。
你学会了吗?
好啦,本章对于《C++:vector基础讲解》的学习就先到这里,如果有什么问题,还请指教指教,希望本篇文章能够对你有所帮助,我们下一篇见!!!
如你喜欢,点点赞就是对我的支持,感谢感谢!!!

相关文章:
C++:vector基础讲解
hello,各位小伙伴,本篇文章跟大家一起学习《C:vector基础讲解》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 ! 如果本篇文章对你有帮助,还请各位点点赞!&#…...
Grafana 路径遍历所有路径 CVE-2021-43798漏洞预警
简介 Grafana是一个跨平台、开源的数据可视化网络应用程序平台。用户配置连接的数据源之后,Grafana可以在网络浏览器里显示数据图表和警告。 漏洞危害等级 高危 CVE 编号 CVE-2021-43798 FOFA查询 app"Grafana" zoomeyes查询 app:"gr…...
基于Docker部署GitLab环境搭建
文件在D:\E\学习文档子目录压缩\专项进阶,如ngnix,webservice,linux,redis等\docker 建议虚拟机内存2G以上 1.下载镜像文件 docker pull beginor/gitlab-ce:11.0.1-ce.0 注意:一定要配置阿里云的加速镜像 创建GitLab 的配置 (etc) 、 日志 (log) 、数…...
初始化是什么
定义 初始化(Initialization)是指在计算机科学和软件开发中,将系统、变量、对象或其他可用组件设置为其初始状态或初始值的过程。这通常是在程序开始执行或组件第一次使用之前进行的,以确保其处于可预测和稳定的状态。 初始化的…...
Python图形界面(GUI)Tkinter笔记(九):用【Button()】功能按钮实现人机交互
在Tkinter库中,功能按钮(Button)是实现人机交互的一个非常重要的组件: 【一】主要可实现功能及意义: (1)响应用户交互: Button组件允许用户通过点击来触发某个事件或动作。当用户点击按钮时,可以执行一个指定的函数或方法。 (2)提供用户输入: Button组件是图形用户界面(G…...
linux 内核安装、切换版本,禁用内核更新
安装内核 版本5.15.0-105 sudo apt-get install linux-image-5.15.0-105-generic sudo apt-get install linux-headers-5.15.0-105-generic切换内核版本 #查看已安装内核版本 grep menuentry /boot/grub/grub.cfg sudo dpkg --get-selections |grep linux-image#修改文件/etc…...
充电桩中PE接地实时监测的一种电路.pdf
pdf下载链接:https://pan.baidu.com/s/18k8tEwa6h3WAOGJs3lAsTQ 提取码:Ronv...
鲲泰新闻丨第七届数字中国建设峰会正式启幕,神州鲲泰携手天翼云共筑智算云生态
2024年5月23日,由国家发展改革委、国家数据局、国家网信办、科技部、国务院国资委、福建省人民政府共同主办的“第七届数字中国建设峰会”在福建省福州市海峡国际会展中心盛大开幕。 数字中国建设峰会是展示数字中国建设成就的盛会,本次峰会以“释放数据…...
零基础学Java第二十二天之IO流之内存流,打印流,随机流
IO流之内存流,打印流,随机流 1、内存流 1、理解 内存流"(Memory Stream)在计算机编程中通常指的是一种特殊的数据流,它在内存中存储和操作数据,而不是在外部存储(如硬盘、网络等…...
vue-router路由懒加载以及三种实现方式
什么是路由懒加载? 延迟加载或按需加载路由所对应的组件,而不是在应用初始化时就一次性加载所有组件。 路由懒加载做了什么事情? 主要作用是将路由对应的组件打包成一个个的js代码块 只有在这个路由被访问到的时候,才加载对应…...
Java轻松转换Markdown文件到Word和PDF文档
Markdown 凭借其简洁易用的特性,成为创建和编辑纯文本文档的常用选择。但某些时候我们需要更加精致的展示效果,例如在专业分享文档或打印成离线使用的纸质版时,就需要将Markdown文件以其他固定的文档格式呈现。通过将 Markdown 转换为 Word 和…...
【JAVA基础之内部类】匿名内部类
🔥作者主页:小林同学的学习笔录 🔥小林同学的专栏:JAVA之基础专栏 目录 1.内部类 1.1 概述 1.1.1 什么是内部类 1.1.2 什么时候使用内部类 1.2 内部类的分类 1.3 成员内部类 1.3.1 获取成员内部类对象的两种方式 1.3.2 经典面试…...
远动通讯屏的原理和应用
远动通讯屏的原理和应用 远动通讯屏,是一种集显示和远程控制于一体的智能化控制设备。它可以通过网络、通信线路等方式实现与远程设备的通讯和交互,从而实现远程监控和控制。 远动通讯屏实现远程控制的核心原理是基于PLC(Programmable Logic …...
C++ (week4):Linux基础
文章目录 零、Linux简介1.配置环境2.Linux历史3.Linux模型 一、vim二、Linux命令行 (shell命令)1.常用命令与快捷键(1)常用命令①man命令:查看帮助手册 (2)快捷键 2.用户子系统(1)Linux用户(2)用户命令 3.文件子系统命令(1)目录命令1.创建文件:mkdir2.删…...
如何将手机中的音乐转移到 SD 卡上?轻松传输音乐
概括 如何将音乐从手机转移到 SD 卡?我们的智能手机可以充当个人点唱机,因此有效管理我们的音乐库变得至关重要。无论您是存储空间不足还是只是想整理您的音乐收藏,将音乐从手机传输到 SD 卡都是一个实用的解决方案。 在本指南中࿰…...
JKTECH柔性振动盘用途
柔性振动盘的作用与用途 在现代工业自动化领域,柔性振动盘凭借其独特的功能和广泛的应用场景,正逐渐成为生产线上的重要工具。柔性振动盘,又称柔性供料器,它结合了传统振动盘的高效性和现代自动化技术的灵活性,为各种…...
【职场心灵伴侣】文心一言智能体
【文心一言】智能体 写在最前面名称和简介:职场心灵伴侣AI生成头像添加工具智能体调优 🌈你好呀!我是 是Yu欸 🌌 2024每日百字篆刻时光,感谢你的陪伴与支持 ~ 🚀 欢迎一起踏上探险之旅,挖掘无限…...
【运维】笔记本电脑风扇清洁
笔记本电脑是我们不可或缺的工具,无论是工作、学习还是娱乐。然而,随着时间的推移,笔记本电脑的性能可能会因为各种原因受到影响,尤其是散热问题。过热不仅会降低性能,还可能缩短硬件的寿命。最近,在使用我…...
3.1 掌握RDD的创建
在Apache Spark中,RDD(Resilient Distributed Dataset)是一个基本的、不可变的、分布式的和可分区的数据集。它能够自动进行容错处理,并支持在大规模集群上的并行操作。RDD之间存在依赖关系,可以实现管道化,…...
深入理解 Java 中的 `volatile` 关键字:可见性与有序性的保障
深入理解 Java 中的 volatile 关键字:可见性与有序性的保障 volatile主要做了两个事情可见性保证 和 有序性 可见性保证就是: 对volatile的写操作会对其他线程可见。 简单来说我们A线程的修改了volatile的值,那么我B线程也可以看见。 有序…...
AI大模型的简历如何写才能拿到面试机会?简历+项目+面试技巧+面试题一套全搞定!
AI大模型的简历如何写才能拿到面试机会?简历项目面试技巧面试题一套全搞定! 一、简历撰写:突出AI大模型核心能力 1. 技术栈明确标注 必写项: 框架:PyTorch、TensorFlow、Hugging Face Transformers、DeepSpeed、Lang…...
纸箱压缩试验机哪个好
在包装行业,纸箱抗压性能直接决定着产品运输安全、仓储效率和企业成本控制。而纸箱压缩试验机(抗压试验机)就是衡量纸箱是否“扛得住”的核心设备。面对市面上琳琅满目的品牌与型号,很多企业主都会问:纸箱压缩试验机哪…...
如何快速部署DeepQA:10分钟搭建你的第一个AI聊天机器人
如何快速部署DeepQA:10分钟搭建你的第一个AI聊天机器人 【免费下载链接】DeepQA My tensorflow implementation of "A neural conversational model", a Deep learning based chatbot 项目地址: https://gitcode.com/gh_mirrors/de/DeepQA DeepQA是…...
116. 为项目监控员生成的警报添加标签
Procedure 程序To label alerts for Project Monitors, you must configure the Prometheus Federator Helm charts values section. This is done by adding additionalRuleLabels under defaultRules within helmProjectOperator. You can perform this modification during…...
实战指南:利用Hydra与SNETCracker加固3389远程桌面安全
1. 3389端口与远程桌面安全基础 3389端口是Windows远程桌面协议(RDP)的默认通信端口,就像你家大门的钥匙孔。想象一下,如果钥匙孔被所有人知道位置,又没装猫眼和防盗链,会是什么后果?这就是为什…...
环境配置实战:从CUDA与PyTorch版本不匹配报错到多版本灵活管理
1. 当PyTorch遇上CUDA:版本冲突的幕后真相 刚跑起来的深度学习代码突然报错"RuntimeError: The detected CUDA version mismatches...",这种场景就像你拿着iPhone充电器想给安卓手机充电——插口根本不匹配。我去年在部署一个图像识别项目时就…...
NSGA-III中的参考点生成与多样性维护机制解析
1. NSGA-III算法中的参考点是什么? 第一次接触NSGA-III算法时,最让我困惑的就是这个"参考点"概念。简单来说,参考点就像是多目标优化问题中的导航灯塔,它们均匀分布在目标空间里,指引算法找到分布均匀的解集…...
tao-8k性能优化小技巧:如何提升向量化与检索速度
tao-8k性能优化小技巧:如何提升向量化与检索速度 1. 理解tao-8k的性能瓶颈 1.1 模型架构特点 tao-8k作为支持8192长度上下文的嵌入模型,其核心优势在于长文本处理能力。然而,这种能力也带来了独特的性能挑战: 计算复杂度&…...
AI大模型大师:2026年AI技术全景,从入门到精通的完整学习指南!人工智能领域大模型学习路径
人工智能领域大模型学习路径 一、基础阶段:构建核心知识框架(1-2个月) 数学与编程基础 数学:掌握线性代数(矩阵运算、特征值分解)、概率论(贝叶斯定理、分布函数)、微积分&#x…...
利用快马平台快速构建openclaw101机器人抓手控制原型,十分钟完成代码框架
最近在做一个机器人抓手的控制项目,正好尝试了用InsCode(快马)平台来快速搭建原型,整个过程比想象中顺利很多。作为一个开源硬件爱好者,我想分享一下如何用这个平台十分钟搞定openclaw101机器人抓手的控制程序框架。 项目背景与需求分析 open…...
