【C++STL详解(三)】------vector的介绍与使用

目录

前言

一、关于数组

二、vector的介绍

三、vector的使用

Ⅰ、默认成员函数

1.构造函数

2.赋值重载

3.析构函数

Ⅱ、容量

1.size()

2.capacity()

3.empty()

4.resize()

5.reserve()

Ⅲ、遍历操作

1.迭代器

begin() +end()(正向迭代器)

rbegin()+rend()(反向迭代器)

2.operator【】

Ⅳ、增删查改

1.push_back()

2.pop_back()

3.find()

4.insert

5.erase

6.swap

四、vector细节问题-迭代器失效

Ⅰ、失效案例

1.会引起底层结构发生改变的操作!

2.指定位置元素的删除操作--erase

Ⅱ、解决方案

Ⅲ、总结


前言

下面接着来介绍C++中容器vector的使用,本文章重点介绍一些常用的接口不是全部接口哦,完整版文档大家可以参照vector文档(建议PC端打开哦!)

一、关于数组

想必在C语言阶段是大家经常使用的数组都是静态的,就像下面这段代码一样

int a[10]={1,2,3,4,5,6,7,8,9,10};

上面就是我们平时喜欢定义的数组,实际上在C++STL库里面也存在着一个容器,array,只不过它是C++11后才提出的,它的出现主要是类比于上面这段数组!

这是它在文档中的介绍,它是一个模板类,参数是非类型模板参数,下面的解释是:它是一个固定大小的序列容器:它们按照严格的线性顺序保存特定数量的元素。说白了就是一个静态数组!

那么它和我们C语言中的静态数组有什么区别呢?其实就是对越界的处理方式不同,来看这两段代码

int a[10];//C语言中的静态数组
array<int,10> a2;//C++的//越界访问是否可行?
a[10];
a[11]=11;//可行?
a2[12];
a2[12]=1;

其实将其放入编译器中C语言的a数组,没有问题正常运行,而C++的这个a2数组程序会直接崩溃!

原因:

①对于C语言的a数组,编译器对其的处理是:越界读没有问题,越界写只是一种抽查,不一定会报错!具有局限性!

②而对于C++提供的array这个容器,对于任意位置的越界读写,程序都会直接结束,它的底层实现用了assert断言!

单从这个角度,C++提供的这个容器很香喷喷,其实不然,它存在的问题就是----开空间过大,会导致栈溢出!而且还不能初始化!又不香了!所以实际中我们一般喜欢使用vector容器,因为它能解决的vector也能解决,vector能解决它不一定能解决!

二、vector的介绍

vector是表示可变大小数组序列容器
就像数组一样,vector也采用的连续存储空间来存储元素,也就是说它可以采用下标对元素进行访问,唯一一点与数组的不同在vector它是动态的,大小会自动的去调整
本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小 为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是 一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
与其它动态序列容器相比(deque, list and forward_list),vector在访问元素的时候更加高效,在末 尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起listforward_list 统一的迭代器和引用更好
ps:这些容器后面都会讲解

三、vector的使用

Ⅰ、默认成员函数

1.构造函数

vector的构造函数常见的有四个:

vector();    //无参构造
vector(size_type n, const value_type& val = value_type());  //构造并初始化n个val
vector (const vector& x);//拷贝构造
vector (InputIterator first, InputIterator last);//迭代器区间构造

具体使用:

vector<int> v1;//无参vector<int> v2(10, 1);//初始化元素为10个1vector<int> v3(v2);//将v2的内容拷贝给v3,并初始化v3vector<int> v4(v2.begin(), v2.begin() + 5);//迭代器区间构造

2.赋值重载

vector& operator= (const vector& x);//使用
vector<int> v2(10, 1);//初始化元素为10个1vector<int> v5=v2;//赋值

3.析构函数

~vector();

一般这个采用自带的就行!

Ⅱ、容量

1.size()

//原型,获取数据个数
size_type size() const;//使用
vector<int> v2(10,1);
cout << v2.size();

2.capacity()

v2.capacity();//获取容量大小

3.empty()

v2.empty();//判空

4.resize()

void resize(size_type n, value_type val = value_type());

调整size的大小,规则如下:

①如果n比当前的size小,那么就会缩小当前的size直至和n相等,其余部分删除

②如果n比当前的size大,那么就会扩充到n,扩充的部分如果没有给出具体的值,则用0代替,反之用具体的值代替!

③如果n大于当前的capacity,则会自动重新分配空间,在将原始数据拷贝到新空间!

①比size小的情况:

②比size大的情况:

5.reserve()

void reserve(size_type n);

调整capacity的大小,规则如下:

①如果n小于当前容量,什么都不做

②如果n大于当前容量,就扩充到和n一样大

Ⅲ、遍历操作

1.迭代器

  • begin() +end()(正向迭代器)

实际上和前面的string类一样的迭代器!

begin():指向的是第一个元素的位置

 iterator begin(); 
 const_iterator begin() const;//为const对象提供的

end(): 指向的是最后一个元素的下一个位置!

iterator end();

const_iterator end() const;

代码实现:

  • rbegin()+rend()(反向迭代器)

rbegin:指向最后一个元素的位置!

reverse_iterator rbegin();

const_reverse_iterator rbegin() const;

rend:指向的是第一个元素的前一个位置!

reverse_iterator rend();

const_reverse_iterator rend() const;

代码实现:

2.operator【】

有了它就能想普通数组那样通过下标去访问特定的元素了!

reference operator[] (size_type n);

const_reference operator[] (size_type n) const;

直接看代码,没啥好说的哥们!

要注意:有了它我们不仅仅是读元素,还可以进行修改与赋值!

Ⅳ、增删查改

1.push_back()

一个简单的尾插操作!

void push_back(const value_type & val);

vector<int> v;
for (int i = 1; i <= 9; i++)
{v.push_back(i);
}

2.pop_back()

简单的尾删操作!

 void pop_back();
 

vector<int> v;
for (int i = 1; i <= 9; i++)
{v.push_back(i);
}v.pop_back();//尾删

3.find()

查找操作!需要注意:这个不是vector成员函数的接口,这个是算法库里面的,把它放在这里是因为它可以和下面的insert、erase操作配合使用!

  它在算法库面实际上是一个模板

可以看到它的功能是:在一个迭代区间里面去寻找特定的val,如果找到这个元素,那就返回当前位置的迭代器;如果找不到,那就返回迭代区间的最后一个位置迭代器!

4.insert

插入操作:在pos位置之前插入一个元素!

可以看到它需要传入对应位置的迭代器!所以就可以配合find()去使用!

直接看操作

①特定位置前插入一个值

②特定位置前插入n个val

③在特定位置前插入一段迭代区间(左闭右开)

一定要注意区间是左闭右开的。vector的动态数组下标都是从0开始的

5.erase

删除操作:删除特定位置或者区间的值!

iterator erase(iterator position);
iterator erase(iterator first, iterator last);

来吧,展示!同样也需要配合find()使用

①删除特定位置的值

②删除特定区间的值(左闭右开)

6.swap

主要是交换两个vector的数据空间!这个是vector内部的成员函数,不是那个算法库里面的全局的vector

    void swap(vector & x);
 

直接上代码:

四、vector细节问题-迭代器失效

首先需要知道一点,迭代器的作用就是让算法不关心底层的设计实现,而行为却像指针那样进行数据的访问和操作。对于vector来说,它的迭代器的底层设计就是原生的指针T*。所以迭代器失效就是指:迭代器底层对应指针所指向的空间被销毁,而却还在使用这块已经释放的空间,最终的结果会导致程序崩溃!

Ⅰ、失效案例

1.会引起底层结构发生改变的操作!

比如:resize、reserve、insert、assgin、push_back等,因为这些操作都可能会存在扩容这一操作!

vector<int> v;
for (int i = 1; i <= 9; i++)
{v.push_back(i);
}vector<int>::iterator it;
it = find(v.begin(), v.end(), 5);v.insert(it, 100, 1);while (it != v.end())
{cout << *it << " ";++it;
}//可行?

结果如下:

很明显,程序崩溃了!原因就是insert操作导致vector扩容了,开辟了新空间,也就是说vector旧的底层空间已经释放,可是it仍然指向那块空间,在对它进行访问时,实际上就是非法访问一块已经释放的空间,那程序必然崩溃!

2.指定位置元素的删除操作--erase

vector<int> v;
for (int i = 1; i <= 5; i++)
{v.push_back(i);
}vector<int>::iterator it;
it = find(v.begin(), v.end(), 3);v.erase(it);
while (it != v.end())
{cout << *it << endl;it++;
}

直接上结果:

和上面一样的结局,但是原因不同。erase它实际上是不改变底层的结构的,因为删除pos位置的元素后,pos位置后面的元素会向前挪动,理论上来讲是不会失效的!但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效 了。

Ⅱ、解决方案

最好的解决方案就是在上述操作的后面不要再使用迭代器了,如果硬是要使用的话,那应该要将迭代器进行更新了再去使用即可!

Ⅲ、总结

  • 迭代器失效的情况在不同的环境下处理结果不一样,上述崩溃的情况是在VS的下的情况,实际上在Linux下没有那么的严格,但是还是应该注意,要用前最好重新去赋值
  • 对于迭代器失效的问题,并不是所有的容器都会存在这个问题,迭代器的失效取决于该容器的底层结构是怎么样的,比如list的insert就没有这样的问题,因为链表底层是不连续的,new出来的,但是它的erase就有存在失效的问题!注意:链表的迭代器失效只会导致当前节点的迭代器失效!(了解底层后就可以理解了)

今天就分享到这里,希望对大家有所帮助!

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

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

相关文章

ubuntu18源码安装postgresql15.2数据库

由于官方的源只能安装到pg10这个版本&#xff0c;整了好一会没有成功就改为源码安装了。 下载源代码源码并解压 wget https://ftp.postgresql.org/pub/source/v15.2/postgresql-15.2.tar.gztar -xf postgresql-15.2.tar.gz cd postgresql-15.2/ 安装C相关开发库和编译工具 ap…

Java解决找出字符串中第一个匹配项的下标

Java解决找出字符串中第一个匹配项的下标 01 题目 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 示…

网络扫描技术

网络扫描技术是信息安全领域中的一项重要技术&#xff0c;它旨在发现网络中的设备、服务、漏洞和配置情况&#xff0c;为安全评估、渗透测试或恶意攻击做准备。以下是几种主要的网络扫描技术&#xff1a; PING扫射&#xff08;Ping sweep&#xff09;&#xff1a; 通过发送ICMP…

element 分页切换时:current-page无效 页数不会跟着一起切换

问题回溯&#xff1a;使用el-pagination组件 选择切换当前分页 页数为2 问题结果&#xff1a;el-pagination组件 当前页切换失败 一直都是 1&#xff0c;接口传参分页数据是2&#xff0c;打印当前分页也是2 解决方案1&#xff1a;使用 current-page参数 .sync 修饰符 解决方案2…

安装nuxt3环境

安装nuxt3&#xff0c;按照nuxt官网&#xff0c;node版本需在18以上 执行 npx nuxilatest init ‘xxx’终端控制台可能会报错&#xff1a; ERROR Error: Failed to download template from registry: Failed to download https://raw.githubusercontent.com/nuxt/starter/temp…

rust将json字符串直接转为map对象或者hashmap对象

有些时候我们还真的不清楚返回的json数据里面到底有哪些数据&#xff0c;数据类型是什么等&#xff0c;这个时候就可以使用批处理的方式将json字符串转为一个对象&#xff0c;然后通过这个对象的get方法来获取json里面的数据。 pub async fn test_json(&self) {let json_st…

STM32的TIM输入捕获和PWMI详解

系列文章目录 STM32单片机系列专栏 C语言术语和结构总结专栏 文章目录 1. IC输入捕获 2. 频率测量 3. 主模式、从模式、触发源选择 4. 输入捕获基本结构 5. PWMI模式 6. 代码示例 6.1 PWM.c 6.2 PWM.h 6.3 IC.c 6.4 IC.h 6.5 完整工程文件 输出比较可以看下面这篇…

numpy+matplotlib绘制阿基米德螺线

【第10次课]实验十一数据可视化及应用】 声明&#xff1a;著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 绘制阿基米德螺线&#xff0c;运行效果如图所示。 参数方程为: x icosi yisini 其中半径i和圆心角i变化一致&#xff0c;取值范围为…

#你觉得未来的智慧工地是什么样子的#

#你觉得未来的智慧工地是什么样子的# 有人说“现阶段的智慧工地都是噱头&#xff0c;实际用处不大”&#xff1b;也有人将智慧工地吹嘘上天。那么&#xff0c;随着技术的发展&#xff0c;你觉得未来的智慧工地会是什么样子呢&#xff1f; 随着大数据时代的到来&#xff0c;未来…

Three.js杂记(十五)—— 汽车展览(下)

在上一篇文章Three.js杂记&#xff08;十四&#xff09;—— 汽车展览上 - 掘金 (juejin.cn)中主要对切换相机不同位置和鼠标拖拽移动相机焦点做了简单的应用。 那么现在聊聊该如何实现汽车模型自带的三种动画展示了&#xff0c;实际上可以是两种汽车前后盖打开和汽车4车门打开…

Java基础:探秘基本数据类型与对象的巧妙转换

作为准备面试的程序员&#xff0c;了解Java的基本数据类型及其与对象之间的转换功能是非常重要的。 本文将深入探讨Java的基本数据类型&#xff0c;介绍基本数据类型和对象之间的转换方式&#xff0c;帮助你更好地准备面试。 Java的基本数据类型 Java的基本数据类型包括以下…

抑郁后的症状表现——XWX-QP大小鼠强迫游泳桶硬件

简单介绍&#xff1a; 大小鼠强迫游泳桶硬件主要用于抗抑郁的研究。适用于大鼠、小鼠或其他实验室动物&#xff0c;通过将实验动物置于一个局限的环境中&#xff0c;动物在该环境中拼命挣扎试图逃跑又无法逃脱&#xff0c;从而提供了一个无可回避的压迫环境&#xff0c;动物的…

如何提取二维码文本信息?文本二维码提取内容的方法

如何分解出二维码中的文本信息呢&#xff1f;很多商家在做活动时会给每个用户生成一个单独的二维码&#xff0c;每一个二维码中有单独的编号信息&#xff0c;那么当我们收集到用户的二维码时&#xff0c;如何操作才能够提取二维码中的编号信息呢&#xff1f;想要解决这个问题可…

双目深度估计原理立体视觉

双目深度估计原理&立体视觉 0. 写在前面1. 双目估计的大致步骤2. 理想双目系统的深度估计公式推导3. 双目标定公式推导4. 极线校正理论推导 0. 写在前面 双目深度估计是通过两个相机的对同一个点的视差来得到给该点的深度。 标准系统的双目深度估计的公式推导需要满足:1)两…

Vue3+ts(day04:watch、watchEffect)

学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/frontlearningNotes 觉得有帮助的同学&#xff0c;可以点心心支持一下哈&#xff08;笔记是根据b站上学习的尚硅谷的前端视频【张天禹老师】&#xff0c;记录一下学习笔记&#xff0c;用于自己复盘&#xff0c;有需要学…

机器学习学习 - 数据预处理

机器学习学习笔记 - 数据预处理 数据预处理是机器学习项目中不可或缺的一环&#xff0c;它涉及到数据的清洗、格式化、归一化、特征提取等一系列操作&#xff0c;以便为后续的模型训练和分析提供高质量的数据集。以下是关于数据预处理的一些关键步骤和注意事项。 一、数据准备…

树莓派5用docker运行Ollama3

书接上回&#xff0c;树莓派5使用1panel安装 Ollama 点击终端就可以进入容器 输入以下代码 ollama run llama3Llama3 是市场推崇的版本。您的 树莓派5上必须至少有 4.7GB 的可用空间&#xff0c;因此用树莓派玩机器学习就必须配置大容量的固态硬盘。用1panel部署网络下载速度…

RTX3090显卡功耗对比

NVIDIA RTX 3090显卡的官方总图形功耗&#xff08;TGP&#xff09;为350瓦。这是公版显卡的设计功耗。然而&#xff0c;在实际使用中&#xff0c;尤其是进行高强度任务如游戏或专业渲染时&#xff0c;其功耗可能会超过这个数值&#xff0c;尤其在超频的情况下。有报告指出&…

vue-cli+vue3+vite+ts 搭建uniapp项目全过程(二)

接上一篇 3、别名配置 代替 ./srccomponents代替./src/components 在 Vite 中&#xff0c; __dirname 并不是一个全局变量&#xff0c;所以在vite.config.ts 文件中无法直接使用。 安装依赖 npm install --save-dev types/node vite.config.ts配置 // vite.config.t…

Python | Leetcode Python题解之第58题最后一个单词的长度

题目&#xff1a; 题解&#xff1a; class Solution:def lengthOfLastWord(self, s: str) -> int:ls[]for i in s.split():ls.append(i)return len(ls[-1])