【C++】---STL之vector详解

【C++】---STL之vector详解

  • 一、vector的介绍:
  • 二、vector的成员函数:
    • 1、vector类的构造函数
    • 2、vector的元素访问符
    • 3、vector的迭代器
    • 4、vector的模版
    • 5、vector的拷贝构造
    • 6、vector的容量
      • (1)vector的增容机制
      • (2)reserve()和resize()
      • (3)size()
      • (4)empty()
    • 7、vector的尾插和尾删
    • 8、vector在任意位置插入与删除
      • (1)插入(insert)
      • (2)删除
    • 9、find()
    • 10、swap()
  • 三、迭代器失效
    • (1)什么是迭代器失效?
    • (2)为什么会出现:迭代器失效问题?
    • (3)如何解决迭代器失效?!
    • (4)迭代器失效的样例

在这里插入图片描述

一、vector的介绍:

二、vector的成员函数:

vector定义:表示可以动态改变大小的数组序列容器!( vector实际上就是一个顺序表

vector的特点:

(1)vector像数组一样拥有连续的储存空间来储存元素,因此可以通过下标访问来访问储存的元素。

然而还有一点,它不像数组,那就是它可以动态改变其自身的大小,而数组是静态的,它改变其自身大

小是容器对容量自动处理的。

(2)vector的空间比实际上所需要储存的空间更大一点, vector的尾插尾删的效率更高一点,而在其

他位置的插入删除效率相对较低一点,因为每次的插入删除都会挪动后面的数据。

1、vector类的构造函数

1、参考文档:
在这里插入图片描述
2、
(1)

//构造空的vector
explicit vector(const allocator_type& alloc = allocator_type());//构造一个vector,有n个元素,每个元素值为val
explicit vector(size_type n, const value_type& val = value_type(),const allocator_type& alloc = allocator_type());//构造一个vector,值为InputIterator的first到last之间的元素
template <class InputIterator>
vector(InputIterator first, InputIterator last,const allocator_type& alloc = allocator_type());//使用x拷贝构造一个vector
vector(const vector& x);

(2)
vector容器的定义元素、构造函数、拷贝构造函数、尾插:

vector<int> v;// 构造一个空的vector容器vector<int> v1(3, 5);// 构造一个元素个数为3,每个元素的初始化为5的容器vector<int> v2(v1.begin(),v1.end());// 构造一个从v1.begin()到v1.end()的v2容器vector<int> v3(v1);// 拷贝构造v.push_back(1);// 对v1空容器进行尾插。v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);

2、vector的元素访问符

#include<iostream>
#include<vector>using namespace std;int main()
{vector<int> v;// 构造一个空的vector容器vector<int> v1(3, 5);// 构造一个元素个数为3,每个元素的初始化为5的容器vector<int> v2(v1.begin(),v1.end());// 构造一个从v1.begin()到v1.end()的v2容器vector<int> v3(v1);// 拷贝构造v.push_back(1);// 对v1空容器进行尾插。v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);// 1、通过访问符[ ]来访问vector容器中的元素:for (size_t i = 0; i <v.size(); i++){cout << v[i] << " ";}cout << endl;return 0;
}

在这里插入图片描述

3、vector的迭代器

1、迭代器是各种容器,无论是连续还是不连续的空间的容器,通用的遍历容器的方式。

(1)可读可写的迭代器:

int main()
{vector<int> v;// 构造一个空的vector容器vector<int> v1(3, 5);// 构造一个元素个数为3,每个元素的初始化为5的容器vector<int> v2(v1.begin(), v1.end());// 构造一个从v1.begin()到v1.end()的v2容器vector<int> v3(v1);// 拷贝构造v.push_back(1);// 对v1空容器进行尾插。v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);// 2、迭代器遍历vectorvector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";it++;}cout << endl;return 0;
}

在这里插入图片描述
(2)只读的迭代器:
在这里插入图片描述
库里面存在:const迭代器,直接用

	// 2、迭代器遍历vectorvector<int>::const_iterator it = v.begin();while (it != v.end()){cout << *it << " ";it++;}cout << endl;

(3)反向迭代器:
在这里插入图片描述

可读可写:

	// 2、反向迭代器遍历vectorvector<int>::reverse_iterator it = v.rbegin();while (it != v.rend()){cout << *it << " ";it++;}cout << endl;

在这里插入图片描述

(4)反向迭代器:只读:

// 2、反向迭代器遍历vectorvector<int>::const_reverse_iterator it = v.rbegin();while (it != v.rend()){cout << *it << " ";it++;}cout << endl;

4、vector的模版

template<class T>
void PrintVector(const vector<T>& v)
{for (auto e : v){cout << e << " ";}cout << endl;
}
int main()
{// 1、定义一个v1的顺序表,里面的数据都是int类型vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);// 调用打印函数:printvectorPrintVector(v1);// 2、定义一个v2的顺序表,里面的数据都是char类型,并且把s1里面的字符串内容,初始化时赋给v2string s1 = "hello world";vector<char> v2(s1.begin(),s1.end());// 调用打印函数:printvectorPrintVector(v2);// 3、定义一个v3的顺序表,里面的数据都是double类型vector<double> v3;v3.push_back(1.1);v3.push_back(2.2);v3.push_back(3.3);v3.push_back(4.4);v3.push_back(5.5);// 调用打印函数:printvectorPrintVector(v3);return 0;
}

在这里插入图片描述

5、vector的拷贝构造

1、拷贝构造:
在这里插入图片描述
2、样例展示:

	string s2("hello vector");vector<string> v4;v4.push_back(string(s2));PrintVector(v4);// 此时v4的内容就是:hello vector// 拷贝构造:vector<string> v5(v4);// 把v4拷贝构造给v5PrintVector(v5);

在这里插入图片描述

6、vector的容量

(1)vector的增容机制

在VS下执行这段代码:

void test_vector3()
{size_t sz;std::vector<int> foo;sz = foo.capacity();std::cout << "making foo grow:\n";for (int i = 0; i < 100; i++){foo.push_back(i);if (sz != foo.capacity()){sz = foo.capacity();std::cout << "capacity changed:" << sz << endl;}}
}

发现增容的过程是大概按照1.5倍增容的:
在这里插入图片描述
同样的代码在linux下运行,发现是2倍增容的!

(2)reserve()和resize()

1、reserve():

void reserve (size_type n);//开辟n个元素空间
void resize (size_type n, value_type val = value_type());
//开辟n个元素空间,并将每个元素默认初始化为val

如果加上reserve(),那么会提前知道要开多少空间,就提前开好了,避免后面再开空间

void test_vector3()
{size_t sz;std::vector<int> foo;sz = foo.capacity();foo.reserve(100);std::cout << "making foo grow:\n";for (int i = 0; i < 100; i++){foo.push_back(i);if (sz != foo.capacity()){sz = foo.capacity();std::cout << "capacity changed:" << sz << endl;}}
}

2、resize():
在这里插入图片描述
(1)样例演示:

vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);PrintVector(v1);// resize()前:v1.resize(3);// 将v1顺序表的元素个数缩小为3个PrintVector(v1);// resize()后:v1.resize(10,0);// 将v1顺序表的元素个数扩大为10个,并且其余多出来的元素初始化为0。PrintVector(v1);// resize()后:

在这里插入图片描述

(3)size()

1、计算顺序表中的·元素个数:

	vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);cout << v1.size() << endl;

在这里插入图片描述

(4)empty()

1、判断顺序表是否为空:

	vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);cout << v1.empty() << endl;vector<int> v2;cout << v2.empty() << endl;

在这里插入图片描述

7、vector的尾插和尾删

	vector<int> v1;v1.push_back(1);//尾插v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);for (auto e : v1){cout << e << " ";}cout << endl;v1.pop_back();v1.pop_back();//尾删2次for (auto e : v1){cout << e << " ";}cout << endl;

在这里插入图片描述

8、vector在任意位置插入与删除

(1)插入(insert)

1、函数的用法理解:

在这里插入图片描述

    vector<double> v5;//插入4个float元素v5.push_back(1.1);v5.push_back(2.2);v5.push_back(3.3);v5.push_back(4.4);v5.push_back(5.5);v5.insert(v5.end(), 6.6);//在v5末尾插入6.6PrintVector(v5);v5.insert(v5.begin(), 2,0);//在v5开头插入2个0PrintVector(v5);vector<double> v6;v6.push_back(7.7);v6.push_back(8.8);v5.insert(v5.begin(), v6.begin(),v6.end());//在v5开头插入v6PrintVector(v5);

(2)删除

1、erase的使用:
在这里插入图片描述
2、特别要注意:erase可能会导致迭代器失效!!!

iterator erase (iterator position);//删除某一位置元素
iterator erase (iterator first, iterator last);//删除迭代器first和last之间的元素
    v5.erase(v5.begin());//删除v5开头元素PrintVector(v5);v5.erase(v5.begin(), v5.begin()+2);//从v5开头删除2个元素PrintVector(v5);

9、find()

1、在迭代器区间内查找元素,find函数实现在algorithm中,可以给所有容器使用,因此要使用find函数,就要include

template <class InputIterator, class T>InputIterator find (InputIterator first, InputIterator last, const T& val);//在InputIterator迭代器first和last区间内查找val元素的位置

注意:迭代器区间是左闭右开,因此能取到第一个位置,但取不到最后一个位置

    vector<double>::iterator pos = find(v5.begin(), v5.begin() + 3, 1.1);//在第一个元素和第四个元素(左闭右开,不包含第四个元素)之间查找值为1.1的元素位置v5.erase(pos);//删除1.1位置的元素,即删除1.1PrintVector(v5);

10、swap()

1、样例展示:

vector<int> v1;v1.push_back(1);//尾插v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);vector<int> v2;v2.push_back(3);v2.push_back(3);v2.push_back(3);v2.push_back(3);v2.push_back(3);v1.swap(v2);cout << "v1:";for (auto e : v1){cout << e << " ";}cout << endl;cout << "v2:";for (auto e : v2){cout << e << " ";}cout << endl;

在这里插入图片描述

三、迭代器失效

(1)什么是迭代器失效?

1、首先明白什么是迭代器?

1.迭代器的主要作用:就是让算法能够不用关心底层的数据结构,它的底层实际上就是一个指针或者是对指针进行了封装

什么是迭代器失效?迭代器变成了“野指针”!

(2)为什么会出现:迭代器失效问题?

2、为什么会存在迭代器失效?

(1)迭代器失效的原因:是因为迭代器指针所指向的空间被销毁了,而使用一块已经被释放的空间。造成的后果就是程序崩溃。

(2)注意:会引起其底层空间操改变的操作都有可能使迭代器失效,比如resize reserve Insert erase push_back等等。

(3)如何解决迭代器失效?!

如何解决迭代器失效?!
在使用前,对迭代器进行重新赋值即可。

1、样例展示:

#include <iostream>
using namespace std;
#include <vector>int main()
{vector<int> v{ 1, 2, 3, 4 };auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)v.erase(it);++it;//  It是一个迭代器,对一块已经释放了空间的迭代器指针进行操作必然会引起程序崩溃。要想程序不崩溃,必须要对迭代器进行重新赋值!}return 0;
}int main()
{vector<int> v{ 1, 2, 3, 4 };auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)it = v.erase(it);// 在迭代器失效前,对迭代器进行重新赋值,即可保证迭代器不会失效。程序不会崩溃。else++it;}return 0;
}

要特别注意,所有容器如果对它底层的空间数据进行改变的话,就有可能引起迭代器失效,常见的有insert和erase。

(4)迭代器失效的样例

1、

#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、

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

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

3、

#include <string>
void TestString(){string s("hello");auto it = s.begin();// 放开之后代码会崩溃,因为resize到20会string会进行扩容// 扩容之后,it指向之前旧空间已经被释放了,该迭代器就失效了// 后序打印时,再访问it指向的空间程序就会崩溃//s.resize(20, '!');while (it != s.end()){cout << *it;++it;}cout << endl;it = s.begin();while (it != s.end()){it = s.erase(it);// 按照下面方式写,运行时程序会崩溃,因为erase(it)之后// it位置的迭代器就失效了// s.erase(it); ++it;}

好了,今天的分享就到这里了
如果对你有帮助,记得点赞👍+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!
在这里插入图片描述

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

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

相关文章

Spring的过滤器、拦截器、切面区别及案例分析

Spring的过滤器、拦截器、切面 三者的区别&#xff0c;以及对应案例分析 一、三者的实现方式 1.1 过滤器 xxxFilter 过滤器的配置比较简单&#xff0c;直接实现Filter接口即可&#xff0c;也可以通过WebFilter注解实现对特定URL的拦截&#xff0c;Filter接口中定义了三个方法…

告别数据丢失,轻松掌握文件自动备份秘籍

在这个数字化高速发展的时代&#xff0c;我们的工作和生活都离不开电脑&#xff0c;而电脑中存储的文件和数据更是至关重要。然而&#xff0c;数据丢失的风险无处不在&#xff0c;可能因为硬件故障、软件崩溃、病毒攻击等原因而导致重要文件丢失。因此&#xff0c;文件自动备份…

Abaqus三维晶体塑性Voronoi泰森多边形晶格建模插件

插件介绍 AbyssFish Voronoi2D&3D 3D V3.0 插件可对Abaqus内已进行网格划分的部件&#xff08;Part&#xff09;生成Voronoi泰森多边形区块。插件可对任意形状的二维或三维部件、任意特征&#xff08;实体或壳&#xff09;、任意单元形状进行指派Voronoi晶格&#xff0c;可…

【STM32F4】按键开关

上一章&#xff0c;我们介绍了STM32F4的IO口作为输出的使用&#xff0c;这一章&#xff0c;将向大家介绍如何使用按键作为输入使用。 &#xff08;一&#xff09;硬件连接 根据正点原子的stm32f4阿波罗开发板&#xff0c;可以看见 按键KEY0连接在PH3上、 KEY1连接在PH2上、 …

SQLite的DBSTAT 虚拟表(三十六)

返回&#xff1a;SQLite—系列文章目录 上一篇:SQLite运行时可加载扩展(三十五&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 1. 概述 DBSTAT 虚拟表是一个只读的同名虚拟表&#xff0c;返回 有关用于存储内容的磁盘空间量的信息 的 SQLite 数据库。 示例用例…

FPGA - ZYNQ 基于Axi_Lite的PS和PL交互

前言 在FPGA - ZYNQ 基于EMIO的PS和PL交互中介绍了ZYNQ 中PS端和PL端交互的开发流程&#xff0c;接下来构建基于基于Axi_Lite的PS和PL交互。 开发流程 Axi_Lite从机 在FPGA - AXI4_Lite&#xff08;实现用户端与axi4_lite之间的交互逻辑&#xff09;中&#xff0c;详解介绍…

性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法

文章目录 一、前言二、加密接口1、什么是SM22、被测接口加密逻辑 三、准备工作四、JMeter 扩展实现步骤1&#xff1a;准备开发环境步骤2&#xff1a;了解实现方法步骤3&#xff1a;runTest 方法步骤4&#xff1a;getDefaultParameters 方法步骤5&#xff1a;setupTest 方法 五、…

HTX迪拜之夜盛大举行:共筑开放、互联的Web3生态系统

4月18日&#xff0c;由HTX、HTX DAO主办&#xff0c;去中心化AI云游戏协议DeepLink赞助的HTX迪拜之夜主题活动“领航者相聚&#xff0c;引领币圈新风向”在迪拜盛大举行。通过在全球第二大加密中心-迪拜的频繁亮相&#xff0c;HTX正积极塑造自己作为行业领导者的形象&#xff0…

Mysql学习一

目录 1.启动数据库&#xff1a; 2.命令行连接到MySQL&#xff08;winr输入cmd&#xff09; 3.MySQL的三重结构&#xff1a; 4.SQL语句分类&#xff1a; 1.启动数据库&#xff1a; winr——输入services.msc进入本地服务 2.命令行连接到MySQL&#xff08;winr输入cmd&#x…

109. Python的turtle库简介

109. Python的turtle库简介 【目录】 文章目录 109. Python的turtle库简介1. 什么是turtle库&#xff1f;2. 用turtle库绘制一个爱心图案3. 库的导入方法3.1 直接导入整个库3.2 从库中导入特定的函数或类3.3 导入库中的所有内容3.4 为导入的库设置别名3.5 为导入的函数或变量设…

阿里巴巴Java开发规范——编程规约(3)

# 阿里巴巴Java开发规范——编程规约&#xff08;3&#xff09; 编程规约 &#xff08;四&#xff09; OOP规约 1.【强制】构造方法里面禁止加入任何业务逻辑&#xff0c;如果有初始化逻辑&#xff0c;请放在 init 方法中 这条编程规范的目的是为了保持代码的清晰性、可读性…

AOP

代理模式 提出问题 现有缺陷 假设我们有一个计算类&#xff0c;里面有加减乘除四个方法&#xff0c;现在我们要为这四个方法添加日志&#xff0c;即在方法执行的前后分别输出一句话&#xff0c;这时我们会发现如下缺陷&#xff1a; 1.对核心业务有干扰。核心业务是加减乘除…

货拉拉0-1数据指标体系构建与应用

目录 一、背景 二、指标体系搭建 2.1 指标设计 2.2 指标体系搭建 2.3 指标维度拆解 三、指标标准化建设 四、指标元数据管理 五、指标应用&未来规划 原文大佬介绍的这篇指标体系构建有借鉴意义&#xff0c;现摘抄下来用作沉淀学习。如有侵权请告知~ 一、背景 指标…

汽车摄像头匿名化处理解决方案,保护信息的安全性和隐私性

随着智能交通和自动驾驶技术的迅猛发展&#xff0c;汽车摄像头已成为现代汽车不可或缺的一部分&#xff0c;摄像头所捕捉的图像信息也引发了日益严峻的信息安全问题。如何在充分利用摄像头功能的同时&#xff0c;保障个人隐私和信息安全&#xff0c;已成为企业亟待解决的问题。…

IP地址定位技术引发的个人隐私保护问题

IP地址定位技术对互联网的影响深远且多面&#xff0c;它不仅改变了网络管理与优化的方式&#xff0c;还极大地推动了在线广告营销、电子商务、地理信息服务等多个领域的发展。然而&#xff0c;与此同时&#xff0c;它也引发了一系列关于个人隐私保护的问题。 首先&#xff0c;I…

vue的学习之用vue写一个hello,vue

根据以下步骤下载vue.js 介绍 — Vue.js 创建一个damo.html &#xff0c;引入vue.js即可 <body><div id"app">{{ message }}</div><!-- Vue --><!-- 开发环境版本&#xff0c;包含了有帮助的命令行警告 --><script src"js/vu…

清华新突破,360°REA重塑多智能体系统:全方位提升复杂任务表现

引言&#xff1a;多智能体系统的新篇章——360REA框架 在多智能体系统的研究领域&#xff0c;最新的进展揭示了一种全新的框架——360REA&#xff08;Reusable Experience Accumulation with 360 Assessment&#xff09;。这一框架的提出&#xff0c;不仅是对现有系统的一次重大…

如何修改WordPress数据库表前缀以提高安全性

WordPress作为世界上最受欢迎的内容管理系统之一&#xff0c;吸引了数以百万计的用户。然而&#xff0c;正因为其广泛的使用&#xff0c;WordPress网站也成为了黑客攻击的目标之一。其中一个最常见的安全漏洞是使用默认的数据库表前缀wp_&#xff0c;使得黑客能够更轻松地进行大…

Oracle交换分区测试

1、用exchange分区表减少初始化过程中对业务中断的影响 2、创建分区表 create table t_p (id number,name varchar2(30),addr varchar2(50)) partition by range(id) (partition p1 values less than(10), partition p2 values less than(20), partition p3 values less …

sql(ctfhub)

一.整数型注入 输入1 输入2 输入2-1&#xff0c;回显为1的结果&#xff0c;说明是数字型&#xff0c;只有数字型才可加减 判断字段数为2 查询数据库 查表 查列 显示flag内容 二.字符型注入 输入1 输入2 输入2-1&#xff0c;说明为字符型&#xff0c;不是数字型 判断闭合方式为…