珠海网站建设创意/滕州seo
迭代器常见问题的汇总
- vector迭代器和list迭代器的使用
- vector迭代器
- list迭代器
- vector迭代器失效问题
- list迭代器失效问题
- vector和list的区别
vector迭代器和list迭代器的使用
学习C++,使用迭代器和了解迭代器失效的原因是每个初学者都需要掌握的,接下来我们就先从使用迭代器开始,帮助大家浅浅的认识一下迭代器究竟是个什么东西
首先有一点我们需要认识到的是,vector和list在内存上是有差异的,vector是连续的一段内存,而list是链表方式建立起来的。
vector迭代器
查询网站–www.cplusplus.com 建议切换到旧版进行查询
因为本篇文章的重点在于了解迭代器的失效问题,所以这里我们只介绍一下前四个的使用,要想了解的更多,还请大家查询相关的文章。
#include <iostream>
#include <vector>
#include <list>
using namespace std;int main()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);//通过迭代器来遍历vector容器auto it = v1.begin();while (it != v1.end()){cout << *it++ << " ";}cout << endl;return 0;
}
我们暂时可以将vector的容器理解成指针,这能更好的帮助我们理解接下来的东西,但是是否真的是指针,是跟编译器有关的,像VS下vector的迭代器就不是指针,而g++下就是使用指针来实现的。
上面我们创建了一个int类型的容器,使用vector就是说明使用的是一段连续的空间(数组),如下图所示:
begin()就是第一个元素的位置,end()就是最后一个元素的下一个位置,这么看的话我们是否觉得使用迭代器还不如直接使用指针呢?但是别忘了vector是被叫作容器的,看下面的一段代码:
vector<string> s1;s1.push_back("holle");s1.push_back("world");s1.push_back("holle");s1.push_back("iterator");auto lt = s1.begin();while (lt != s1.end()){cout << *lt++ << " ";}cout << endl;
这次我们在容器中放入的是字符串类型,而不是内置类型,这在使用传统的数组是无法办到的,这才是vector容器的价值体现,所以我们C++才需要封装一个叫迭代器的东西以便我们在面对不同的容器的时候都能通过同样的方式去遍历和访问,这一点在list中的体现更大。
list迭代器
list<int> ls;//链表ls.push_back(1);ls.push_back(2);ls.push_back(3);ls.push_back(4);ls.push_back(5);auto LT = ls.begin();while (LT != ls.end()){cout << *LT++ << " ";}cout << endl;
在使用上是看不出来vector和list的迭代器的差别的,但是我们细想一下的话,就能发现其中并不是那么简单的!
list是一种带头双向循环的链表,那么每个结点就有三个区域
指向下一个结点的next指针
指向前一个结点的prev指针和
数据域data
如图:
这时如果我们还将迭代器简单的理解为指针的话,那么不妨想一下,如果我们使用++运算符的话,还能找到下一个结点的位置吗?答案是不能的,因为list不像vector一样是一段连续的内存空间,我们如果还以为迭代器是指针的话,那么++的位置只能是结点的下一个位置,但这个位置极大的概率不是下一个结点的位置。
为什么说极大的概率呢?虽然list构建链表的时候,使用的是空间碎片构建的,但是不排除正好是使用的连续的两块地址空间构造的。
那又为什么我们却能像vector一样的去使用list的迭代器呢?
而且*就是访问的数据,++和- -就能找到结点的后一个结点和前一个结点。
这都归功于类的封装,在对迭代器封装的时候,重新的定义了这些符号的意义(++, - - , *)
也就是符号的重载。这才使得我们能就像使用指针一样去使用迭代器,但实际上它们的底层早已千差万别。
迭代器的封装具体是怎做到,可以看一下这里的代码(list的模拟实现),这里就模拟了一份迭代器的封装,重要的不是看懂这些代码,而是认识到迭代器并不是简单的指针
代码:
//结点template<class T>struct list_node{list_node* next;list_node* prev;T _data;list_node(const T& x = T())//所以要实现默认构造函数:next(nullptr), prev(nullptr), _data(x){}};// 1、迭代器要么就是原生指针// 2、迭代器要么就是自定义类型对原生指针的封装,模拟指针的行为//这里如果单纯的使用结点的指针作为迭代器的话,是没法用++等操作符操作的,所以我们对结点的迭代器进行了//封装!!!template<class T, class Ref, class Ptr>//模板参数一个一个的去理解 1.先不考虑const对象的情况struct _list_iterator{//迭代器内部并不需要进行析构,因为这个类对结点的指针进行了封装,以便我们能够更好的访问链表typedef list_node<T> node;node* _node;typedef _list_iterator<T, Ref, Ptr> self;//构造出一个结点的指针,初始化这个指针的指向为我们想要的结点的位置_list_iterator(node* n):_node(n){}//const T* operator->()Ptr operator->() //优雅!{return &_node->_data;//取地址}Ref operator*() //Ref-->const T& / Ref-->T& !!!!优雅{return _node->_data;}self& operator++() //前置++{_node = _node->next;return *this;}self operator++(int) //后置++{self temp(*this);_node = _node->next;return temp;//返回的是++之前的位置,也就是原来的位置,但是迭代器已经向后移动了}self& operator--(){_node = _node->prev;return *this;}self operator--(int){self temp(*this);_node = _node->prev;return temp;}//bool operator!=(self n)//权限的放大和缩小只针对引用和指针类型bool operator!=(const self& n){return _node != n._node;}bool operator==(const self& n){return _node == n._node;}};template<class T>class list{typedef list_node<T> node;public://第三个模板参数是类型指针,为了重载->时使用typedef _list_iterator<T, T&, T*> iterator;typedef _list_iterator<T, const T&, T*> const_iterator;void empty_init(){_head = new node;_head->next = _head;_head->prev = _head;}//构造函数--创建头结点list(){empty_init();}template<class iterator>list(iterator first, iterator second){empty_init();while (first != second){push_back(*first);++first;}}void swap(list<T>& temp){std::swap(_head, temp._head);}list(const list<T>& lt){empty_init();list<T> temp(lt.begin(), lt.end());swap(temp);}/*list(const list<T>& lt){empty_init();for (auto e : lt){push_back(e);}}*/list<T>& operator=(list<T> lt)//这里不能使用引用,会改变原来list的数据{swap(lt);return *this;}~list(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){//it = erase(it);erase(it++);//后置++}}iterator begin(){return iterator(_head->next);//头结点的下一个就是第一个结点的位置}iterator end(){return iterator(_head);//头结点就是end结点的位置}const_iterator begin() const{return const_iterator(_head->next);}const_iterator end() const{return const_iterator(_head);}void insert(iterator pos, const T& val){node* cur = pos._node;//当前位置node* pre = cur->prev;//pos的前一个位置node* new_node = new node(val);//开始插入pre->next = new_node;new_node->prev = pre;new_node->next = cur;cur->prev = new_node;}iterator erase(iterator pos){assert(pos != _head);node* pre = pos._node->prev;//pos位置的前一个node* next = pos._node->next;//pos位置的后一个pre->next = next;next->prev = pre;delete pos._node;return iterator(next);//返回的是删除位置的下一个位置}void push_back(const T& val){创建结点//node* new_node = new node(val);//node* tail = _head->prev;//链表的最后一个结点的位置尾插过程//tail->next = new_node;//new_node->prev = tail;//new_node->next = _head;//_head->prev = new_node;insert(end(), val);//复用}void pop_back(){//erase(_head->prev);erase(--end());}void push_front(const T& val){//insert(_head->next);insert(begin(), val);}void pop_front(){//erase(_head->next);erase(begin());}private:node* _head;//头结点指针};
这份代码也是模拟实现list的完整代码。
vector迭代器失效问题
int main()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);//通过迭代器来遍历vector容器auto it = find(v1.begin(), v1.end(), 3);//在begin()--end()的区间内查找1v1.erase(it);v1.insert(it, 0);for (auto e : v1){cout << e << " ";}cout << endl;
}
上面代码的意思就是找到3的并删除掉他,然后再在该位置插入0。
按照理解这段代码应该是没有问题的,就是很简单的一段删除和插入嘛。
结果:
代码崩了?
这里就是很典型的迭代器失效问题,迭代器it原本指向的是3的位置,之后我们将他删除后,it指向的数据是4,不再是原数据了,这就是迭代器的失效。对于迭代器失效VS是assert断言处理的,所以我们才看到上面的信息。
同样- -也会导致一样的问题。
解决办法就是it接收一下erase的返回值,erase的返回值是该位置的下一个位置的迭代器。这样就能有效的避免上面的问题。
还有一种迭代器失效是在insert时导致的。
假如我们一开始的容器大小是5个,且这个容器已经满了,此时我再进行insert的时候,就会发生扩容。
而C++的扩容是异地扩容的,并没有像C语言的realloc函数一样的接口。
异地扩容就必定会导致一个问题,我们原来it指向的地址发生了改变,此时如果不做处理的话,it指向的就是一块未知的空间,it就变成了一个野指针,这也是一种迭代器的失效。
这个问题在大家模拟实现vector的时候是特别需要注意的一点。
list迭代器失效问题
list的迭代器在删除时也会导致和上面相同的问题,解决办法也是接受一下erase的返回值,同样list的erase的返回值也是该位置的下一个结点位置(next)。
但是list在插入的时候并不会导致迭代器失效,因为list不存在扩容的概念。
list就不存在扩容的问题了。
vector和list的区别
-
vector可以随机访问,通过[ ],而list不支持随机访问。vector访问某个元素的效率为O(1)
list访问某个元素的效率为O(n)。 -
vector中插入和删除都可能导致迭代器失效,而list中插入元素不会导致迭代器失效,删除元素会导致迭代器失效;
vector中插入元素有可能需要增容,迭代器指向的之前的空间会被释放,之前的迭代器会失效;删除元素也会导致迭代器失效;
list中插入元素只是添加了一个新的节点,不会导致之前存在的迭代器失效,而删除元素只会导致当前迭代器失效,其他迭代器不会受到影响。 -
vector中的迭代器是原生态指针,也就是元素类型的指针(vs下不是,g++是); list中的迭代器是对原生态指针(节点指针)的封装;
相关文章:

C++:vector和list的迭代器区别和常见迭代器失效问题
迭代器常见问题的汇总vector迭代器和list迭代器的使用vector迭代器list迭代器vector迭代器失效问题list迭代器失效问题vector和list的区别vector迭代器和list迭代器的使用 学习C,使用迭代器和了解迭代器失效的原因是每个初学者都需要掌握的,接下来我们就…...

SpringSecurity如何实现前后端分离
前后端分离模式是指由前端控制页面路由,后端接口也不再返回html数据,而是直接返回业务数据,数据一般是JSON格式。Spring Security默认的表单登录方式,在未登录或登录成功时会发起页面重定向,在提交登录数据时ÿ…...

为ubuntu 18.04添加蓝牙驱动
目录背景方法背景 从网上买的能直接插ubuntu 1804的usb蓝牙太少了,而且还贵。我就直接从JD下单的一个便宜的USB蓝牙,结果插上机器没有驱动起不来。我的PC是个3年前的老机器,实在是不想升级系统,于是捣鼓半天捣鼓好了,…...

Stable Diffusion Prompt用法
Stable Diffusion可以根据你输入的提示词(prompt)来绘制出想象中的画面。 1、正向提示词(Prompt): 提高图像质量的prompt: prompt用途HDR, UHD, 64K(HDR、UHD、4K、8K和64K)这样的质量词可以带来巨大的差异提升照片…...

jenkins问题
目录 python 不是内部或外部命令,也不是可运行的程序 ‘cmd’ 不是内部或外部命令,也不是可运行的程序或批处理文件。 git 不是内部或外部命令,也不是可运行的程序或批处理文件。 pywintypes.com_error: (-2147024891, ‘拒绝访问。’, None,…...

阅读笔记DeepAR: Probabilistic Forecasting with Autoregressive Recurrent Networks
zi,t∈Rz_{i,t}\in \mathbb{R}zi,t∈R表示时间序列iii在ttt时刻的值。给一个连续时间段t∈[1,T]t\in [1, T]t∈[1,T],将其划分为context window[1,t0)[1,t_0)[1,t0)和prediction window[t0,T][t_0,T][t0,T]。用context window的时间序列预测prediction window…...

01.Java的安装
1.JDK&JREJDK : Java SE Development Kit--Java开发工具JRE : Java Runtime Environment--Java运行环境Java编程,需要安装JDK;如果仅仅是运行一款Java程序则只需要运行JREJava的安装包分为两类:一类是JRE--是一个独立的Java运行环境; 一类…...

【C语言深度剖析】关键字(全)
文章目录一.存储类型关键字前言补充1:内存思考:补充2:变量与内存的关系补充3:变量的分类补充4:存储类补充5:删除数据是怎么删除的?1.auto2.register3.static4.extern基本用法:基本功能5.typedef…...

English Learning - L2 语音作业打卡 双元音 [aʊ] [əʊ] Day15 2023.3.7 周二
English Learning - L2 语音作业打卡 双元音 [aʊ] [əʊ] Day15 2023.3.7 周二💌发音小贴士:💌当日目标音发音规则/技巧:🍭 Part 1【热身练习】🍭 Part2【练习内容】🍭【练习感受】🍓元音 /eɪ…...

记第一次面试的过程(C++)
说实话三月份上旬过得很充实,而且感觉蛮值,但还有不足的地方,今晚特地看完资料分析来复盘复盘。 时间还要回到3.2中午13.35(别问我为什么那么准确,刚刚掏手机看的),我正在吃着饭看着王者荣耀的直…...

06 电力电子仿真 MATLAB/Simulink
文章目录01 单相半波整流电路02 单相全波整流电路(子系统封装模块)03 三相桥式整流电路(三相模块与示波器使用)04 相控与斩控交交调压(THD计算)05 Buck电路(PWM实现与闭环反馈)06 单…...

搞懂面向对象这五大概念,才算真正跨过初学者到开发者的“分水岭“
文章目录前言一、对象二、类三、面向对象程序设计的特点1. 封装2. 继承3. 多态前言 面向对象程序设计是在面向过程程序设计的基础上发展而来的,它比面向过程编程具有更强的灵活性和扩展性。面向对象程序设计也是一个程序员发展的 “分水岭”,很多的初学者…...

基于DelayQueue实现的延时队列
基于java中延时队列的实现该文章,我们这次主要是来实现基于DelayQueue实现的延时队列。 使用DelayQueue实现的延时队列的步骤: 定义一个继承了Delayed的类,定义其中的属性,并重写compareTo和getDelay两个方法创建一个Delayqueue…...

MATLAB实现层次分析法AHP及案例分析
层次分析法(Analytic Hierarchy Process, AHP) 1 模型背景 美国运筹学家匹兹堡大学教授Saaty在20世纪70年代初提出的一种层次权重决策分析方法。 层次分析法(Analytic Hierarchy Process, AHP)是一种定性和定量分析相结合的决策分析方法。 特点:用较少的定量信息使决策的…...

Vue 3.0 TypeScript支持
Vue CLI 提供内置的 TypeScript 工具支持。 #NPM 包中的官方声明 随着应用的增长,静态类型系统可以帮助防止许多潜在的运行时错误,这就是为什么 Vue 3 是用 TypeScript 编写的。这意味着在 Vue 中使用 TypeScript 不需要任何其他工具——它具有一流的公…...

STM8S系列基于IAR标准外设printf输出demo
STM8S系列基于IAR标准外设printf输出demo📌STM8S/A标准外设库(库版本V2.3.1)📍官网标准外设库:https://www.st.com/zh/embedded-software/stsw-stm8069.html ⛳注意事项 🚩在内存空间比较有限的情况下&am…...

PMP项目管理项目质量管理
目录1 项目质量管理概述2 规划质量管理3 管理质量4 控制质量1 项目质量管理概述 项目质量管理包括把组织的质量政策应用于规则、管理、控制项目和产品质量要求,以满足相关方目标的各个过程。项目质量管理还将以组织的名义支持过程的持续改进活动。 核心概念 质量是…...

前缀和总结
前缀和是一个常用的算法技巧,通常用于求解数组或序列的区间和。 具体来说,假设有一个长度为n的数组a,我们可以预处理出一个长度为n+1的前缀和数组s,其中s[i]表示原数组a前i个元素的和,即: s[i] = a[0] + a[1] + ... + a[i-1] 这样一来,对于任意的区间[l, r],我们可以…...

0109二分图-无向图-数据结构和算法(Java)
文章目录1 概念2 API3 分析和实现4 测试5 总结后记1 概念 二分图是一种能将所有结点分为两部分的图,其中图的每条边所连接的两个顶点都分别属于不同的部分。 2 API public classBipartiteBipartite(Graph G)预处理函数public booleanisBipartitle()是否是二分图pub…...

计算机网络题库---选择题刷题训练(100多道精品)
第一章 概述 1.下列四项内容中,不属于Internet(因特网)基本功能是___D_____。 A.电子邮件 B.文件传输 C.远程登录 D.实时监测控制 2.Internet是建立在____C_____协议集上的国际互联网络。 A.IPX B.NetBEUI C.TCP/IP …...

16、字符串生成器
目录 (1)append()方法 (2)insert(int offset, arg)方法 (3)delete(int start , int end)方法 创建成功的字符串对象,其长度是固定的,内容不能被改变和编译。虽然使用“”可以达到…...

docker基本命令-容器
容器 基本概念 镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。 容…...

QT入门基础(一)
文章目录零.Qt背景1.什么是Qt2.Qt的发展史3.Qt的优势4.Qt应用一.第一个Qt程序0.项目创建1.main函数文件2.类头文件3.pro文件4.qt命名规范二.Qt按钮1.按钮创建和父子关系2.按钮常用api3.Qt窗口坐标体系4.对象树模型零.Qt背景 1.什么是Qt Qt是一个跨平台的C图形用户界面应用程序…...

WattOS:一个稳又快的轻量级 Linux 发行版
导读Linux 领域里的每个人不是听说过就是使用过某个轻量级的 Linux 发行版。大家都知道我们不断追求的是:占用内存少,配置资源要求低,包含一个轻量级的桌面环境(或者窗口管理器),并且提供和其他发行版相似的…...

Java调用Python脚本:轻松实现两种语言的互操作性
Java和Python都是非常流行的编程语言,它们都有自己的优点,但也有自己的局限性。在编写应用程序时,我们可能需要使用两种语言来共同完成一项任务。在这种情况下,Java需要调用Python脚本来解决某些问题,同时利用Java和Py…...

未系安全带识别系统 yolo
未系安全带识别系统通过pythonyolo智能视频分析技术,未系安全带识别算法对画面中高空作业人员未系安全带行为进行监测,未系安全带识别算法监测到人员未穿戴安全带时,立即通知后台人员及时处理触发告警。Yolo算法采用一个单独的CNN模型实现end…...

(七十六)大白话MySQL是如何根据成本优化选择执行计划的?(上)
之前已经给大家讲解清楚了 MySQL 在执行单表查询时候的一些执行计划,比如说const、ref、range、index、all之类的,也讲了多表关联的时候是如何执行的,本质其实就是先查一个驱动表,接着根据连接条件去被驱动表里循环查询࿰…...
DSRC技术
DSRC(Dedicated Short Range Communication)专用短程通信 定位 是V2X领域存在的两大通信技术之一(另一个为LTE-V2X)。 所属技术路线 与这两大技术相对应,是V2X无线通信技术的两大技术路线: IEEE 802.11p 本是04年指定的一个通…...

_面经问题_
一、Java编程语言 Java语言有哪些特点? JVM vs JDK vs JRE 什么是字节码? 采用字节码的好处是什么? 为什么不全部使用AOT呢? 为什么说Java语言"编译与解释并存"? Oracle JDK vs OpenJDK Java和C的区别? 注释有哪几种形式? 标识符和关键字的区别是什么? Jav…...

刷题记录(2023.3.6 - 2023.3.11)
我很喜欢这周的感觉,前两道题对着 wp 简略复现了一下,由于以前都是自己学习,对一些稍微多、稍微难的题都会马上避开,笨小孩逃避太久了,有些事逃不掉,总得面对,开始往往很难,多花点时…...