C C++最新C++ stl迭代器 (迭代器失效问题)_c+(1),2024年最新附超全教程文档

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

迭代器 和 指针

🥦 迭代器所表现出的功能很像指针,但并不能和指针划等号; 迭代器并不是指针,而是类模板,表现的像指针。
  他只是模拟了指针的一些功能,重载了指针的一些操作符,–>、++、–等。迭代器封装了指针,是一个"可遍历STL( Standard Template Library)容器内全部或部分元素"的对象,本质是封装了原生指针 (T*),是指针概念的一种提升,提供了比指针更高级的行为,相当于一种智能指针,他可以根据不同类型的数据结构来实现不同的++,–等操作。

🍊迭代器返回的是对象引用而不是对象的值,所以cout只能输出迭代器使用取值后的值而不能直接输出其自身。

指针是迭代器的一种形式,迭代器和指针有类似的元素操作功能
相同点
🍒 都可以进行整数操作的加减运算; 都可以同类型相减得到元素个数

区别
迭代器:
🥑 迭代器不是指针是类模版,表现像指针。迭代器是指针的抽象和泛化,它模拟了一些指针的功能, 通过重载指针的一些操作符。本质是封装了原生指针,相当于指针的一种升级。
🥑 迭代器返回的是对象引用而不是对象的值
🥑 指针能指向函数;而迭代器只能指向容器。
🥑 指针只能用于某些特定的容器;迭代器是指针的抽象和泛化。

迭代器失效

🥦 其实迭代器底层对应指针所指向的空间被销毁了,而使用非法的空间造成错误, 可能会导致程序崩溃的后果。
在这里插入图片描述

           		      vs2013 中的迭代器失效

迭代器失效情况

用容器迭代器erase失效情形如下。

🥦 对于序列容器vectordeque来说,使用erase后,后边的每个元素的迭代器都会失效,后边每个元素都往前移动一位,erase返回下一个有效的迭代器。

deque迭代器失效

在这里插入图片描述

其中插入头尾操作引用不失效的原因是,deque由一个map和连续数组组成,其中map是指向数组的指针即二级指针,当插入头尾时,如果内存不够,会①复制原map的信息②申请新的连续空间作为map③存入旧的map信息,然后再插入新的数据。而deque的迭代器中存放着cur(当前数组的位置)first和end(当前map节点的首位地址)和node(当前map的节点地址),所以由于map的从新分配,迭代器的node失效,但是原map指向的连续数组并没有从新分配。
在这里插入图片描述

🍊 对于关联容器mapset来说,使用了erase后,当前元素的迭代器失效,但是其结构是红黑树,删除当前元素,不会影响下一个元素的迭代器,所以在调用erase之前,记录下一个元素的迭代器即可。(解决方式)

list迭代器失效

🍉 list迭代器失效即迭代器所指向的那个结点失效了,即该结点被删除了。对于list来说,底层结构为带头双向循环链表,它使用了不连续分配的内存。插入并不会导致迭代器的失效,不会扩容开辟新空间。只有在删除的时候才会失效,并且失效的只是指向被删除结点的迭代器,其它的迭代器并不会收到影响。
  对比vector迭代器,vector底层结构是一个数组,是一段连续的空间。当进行插入需要扩容时,会进行深拷贝,扩容开辟新空间,而迭代器还指向旧空间,就导致迭代器失效了。

详解vector迭代器失效

vector 为例, 对于 vector 可能会导致迭代器失效的操作有:

  1. 会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、push_back…

在这里插入图片描述
与VS相同的代码在Linux中“正常执行”,没有出现崩溃。
在这里插入图片描述
(因为在 windows 中 VS是PJ版本STL,而在Linux g++是SGI版本STL)两种STL版本不同也导致迭代器失效的结果不同,VS较Linux中检查较严格,更容易直接报出错误, 而在Linux中在出现较严重的非法访问时也会出现Segmentation fault
(结果如下图)
在这里插入图片描述

解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给my_it重新赋值即可

int main()
{
	vector<int> v{ 1, 2, 3, 4, 5, 6, 7 }; //C++ 11语法
	vector<int>::iterator my_it = v.begin();
	
	//可能导致容量改变,导致原空间被回收
	//v.insert(v.begin(), 0);
    //v.resize(50, 0);
	//v.reserve(100);
	//v.assign(100, 8);
	v.push\_back(8);
	while (my_it != v.end()){
		cout << \*my_it << endl;
		++my_it;
	}
	return 0;
}

  1. 任意位置元素的删除操作–erase

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
:当迭代器的值为0时,此时会进行删除,删除后如果迭代器不重新赋值,会导致原来的迭代器失效,此时针对一个已经失效的迭代器在进行++,会导致程序崩溃

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

int main()
{
	int a[] = { 1, 2, 3, 4 };
	vector<int> v(a, a + sizeof(a)/sizeof(int));
	// 使用find查找3所在位置的iterator
	auto pos = find(v.begin(), v.end(), 2);
	// 删除pos位置的数据,导致pos迭代器失效。
	v.erase(pos);
	cout << \*pos << endl; // 此处会导致非法访问
	return 0;
}
_________________________________________________________________________

int main()
{
	int ar[] = { 1, 2, 3, 4, 0, 5, 6, 7, 8, 9 };
	int n = sizeof(ar) / sizeof(int);
	vector<int> v(ar, ar + n);
	vector<int>::iterator it = v.begin();
	while (it != v.end()){
		if (\*it != 0)
			cout << \*it;
		else
			v.erase(it);
		it++;
	}
	return 0;
}


![img](https://img-blog.csdnimg.cn/img_convert/ca635f22cf284862bb25cda08c1ce816.png)
![img](https://img-blog.csdnimg.cn/img_convert/d9fde4aad6590fff24eb4ae0e4c2350d.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 15
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值