vector迭代器失效

目录

迭代器失效的场景

insert插入元素时迭代器失效

erase删除元素时迭代器失效


本期我们主要进行vector迭代器失效问题的讨论。

迭代器失效的场景

insert插入元素时迭代器失效

先看代码:

cpp 复制代码
iterator insert(iterator pos, T val)
		{
			assert(pos >= _start);
			assert(pos <= _finish);
			size_t length = pos - _start;
			if (_finish == _endofstorage)
			{
				reserve(capacity() == 0 ? 4 : capacity() * 2);
			}
			pos = _start + length;
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				end--;
			}
			_finish--;
			*pos = val;
			return pos;
		}

insert插入元素时为什么会导致迭代器时效呢?其实这主要是在插入元素时,空间不够,扩容导致的。

**解析:**如图,假设在pos位置插入一个元素,但是此时空间不够,所以我们进行了扩容。但是扩容之后此时的pos仍然指向了之前的位置,所以此时的pos就已经失效了(这就称作迭代器失效),所以我们得通过pos-_start的值计算出来pos位置与_start的位置,然后在扩容之后,通过差值计算出来真正的pos的位置。需要注意的是,我们此时的正确位置只是形参里pos的正确位置,但是实参是没有发生变化的,因为insert形参列表中的pos位置传的是实参pos的值,所以我们得通过返回值的方式返回扩容后正确的pos位置。

erase删除元素时迭代器失效

我们要删除vector中的偶数元素,此时erase失效场景有三种:

第一种:

解析 :思想:我们要删除所有的偶数所以先让pos指向第一个元素的位置,如果不是偶数就 + +如果pos位置的元素是偶数就删除pos 位置的元素,删除元素的思想其实就是把要删除的元素的后面的所有元素统一往前移动一个位置,这样就删除了要删除的元素。对于第一种情景,我们发现,确实是删除了所有的偶数。
注意: end表示最后一个元素的位置的下一个位置。

第二种:

**解析:**跟第一种情景的思想是一样的,但是到最后会产生迭代器失效,在删除了元素之后,我们会先将指向了删除了的元素的位置的指针+ +,然后再将finish--但是这样会产生一种极端的情况,如图,就是当最后一个元素是偶数时,我们将最后一个元素删除之后,先将指向了最后一个元素的指针++,然后将finish--,这就导致了pos和 finish错位,因为循环的终止条件是pos<_finish,因为pos和 finish错位,这就导致循环不会终止,所以这种情况是有问题的。

第三种:

**解析:**这种情景我们称作连续偶数的情景,在这种情景下,同样是因为,我们再删除完了元素之后先++了pos,因为删除的本质就是将删除位置的元素后面的所有元素统一往前移动一格位置,就会导致要删除的位置的元素被删除之后,要删除的元素的下一个元素就自动的移动到了要删除的元素的位置上,但是我们仍然++pos,就会导致删除的元素的下一个元素被无意间跳过,这就导致了要删除的元素的下一个元素永远无法删除,这便是这种情景没有完全删除所有的偶数元素的原因。

在这三种情形下迭代器都已经失效了,那么我们该怎样去进行代码的修改呢?直接代码:

cpp 复制代码
iterator  erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);

			iterator begin = pos;
			while (begin < _finish - 1)
			{
				*begin = *(begin + 1);
				begin++;
			}
			--_finish;
			//这里要返回pos位置上的数据,是因为,可能会跳过元素,这里有几种情况,所以我们必须返回删除之后,正确的迭代器的位置,所以我们要返回pos
			// 1 2 3 4 5 -> 正常
			// 1 2 3 4   -> 崩溃
			// 1 2 4 5   -> 没删除完
			return pos;
		}

这是删除元素的代码,我们用迭代器作为返回值的原因是因为,要返回删除的元素的下一个元素的位置,但是因为删除的思想,会导致要删除的元素后面的所有元素统一往前移动一个位置,所以要删除的元素的下一个元素的位置其实就是pos位置。

原始版本:

cpp 复制代码
void test1()
	{
		vector<int> v1;
		v1.pushback(1);
		v1.pushback(2);
		v1.pushback(4);
		v1.pushback(5);
	    vector<int>::iterator pos= v1.begin();
		while (pos != v1.end())
		{
			if (*pos % 2 == 0)
			{
				v1.erase(it);
			}

			++pos;
		}
	}

每次删掉元素都要进行迭代器的++,导致迭代器失效。

改进版本:

cpp 复制代码
void test1()
	{
		vector<int> v1;
		v1.pushback(1);
		v1.pushback(2);
		v1.pushback(4);
		v1.pushback(5);
		vector<int>::iterator pos =v1.begin();
		while (pos != v1.end())
		{
			if (*pos % 2 == 0)
			{
				pos = v1.erase(pos);
			}
			else
			{
				++pos;
			}
		}
	}
}

改进了之后,再删除掉元素之后,不直接++,而是返回要删除的元素的下一个元素的位置作为pos迭代器的值(采用这种方式的原因吗,其实还要为缩容去考虑,不然完全可以删除完之后不返回任何值)。

编译器缩容场景的迭代器失效很少见到,所以我们就不做介绍。

本期内容到此结束^_^

相关推荐
uyeonashi6 分钟前
【Boost搜索引擎】构建Boost站内搜索引擎实践
开发语言·c++·搜索引擎
再睡一夏就好9 分钟前
从硬件角度理解“Linux下一切皆文件“,详解用户级缓冲区
linux·服务器·c语言·开发语言·学习笔记
TIF星空1 小时前
【使用 C# 获取 USB 设备信息及进行通信】
开发语言·经验分享·笔记·学习·microsoft·c#
Smile丶凉轩3 小时前
Qt 界面优化(绘图)
开发语言·数据库·c++·qt
reasonsummer4 小时前
【办公类-100-01】20250515手机导出教学照片,自动上传csdn+最大化、最小化Vs界面
开发语言·python
small_wh1te_coder5 小时前
从经典力扣题发掘DFS与记忆化搜索的本质 -从矩阵最长递增路径入手 一步步探究dfs思维优化与编程深度思考
c语言·数据结构·c++·stm32·算法·leetcode·深度优先
苏三福5 小时前
ros2 hunmle bag 数据包转为图片数据 python版
开发语言·python·ros2humble
qqxhb6 小时前
零基础学Java——第十一章:实战项目 - 桌面应用开发(JavaFX入门)
java·开发语言·javafx
大神薯条老师6 小时前
Python零基础入门到高手8.4节: 元组与列表的区别
开发语言·爬虫·python·深度学习·机器学习·数据分析
z人间防沉迷k6 小时前
堆(Heap)
开发语言·数据结构·笔记·python·算法