迭代器失效(附案例详解)


本文将使用具体案例来详细解读迭代器失效的各种原因

迭代器指向内容意义改变

下面我们看一段代码

int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	//查找3迭代器的位置
	vector<int>::iterator pos = find(v.begin(), v.end(), 3);	
	if (pos != v.end())
	{
		v.insert(pos, 10);		//在3之前插入10
	}
	PrintVector(v);
	v.erase(pos);
	PrintVector(v);
	return 0;
}

在3之前插入10后,我们又想将pos位置的3删除掉。
可是问题来了,这样的代码真的可以按照我们的想法进行吗?在我们执行代码后,我们发现并没有发生我们所预期的结果
在这里插入图片描述

jjfiah很明显,这样的代码是错误的,而这里错误的原因就是迭代器意义改变的一种迭代器失效。
jjfiah那么具体的错误是如何发生的呢?答案就是,在我们进行insert后,pos将不会再指向3,而是指向刚刚插入的10。
在这里插入图片描述
jjfiah假如说,插入之前pos的值是0x11223344,在插入10后,由于3-5这些数字要往后挪动,于是10就被放置在原先3的位置,而pos并没有随着3位置的改变而改变,因此,pos指向的就是10。pos代表的含义就变了

总结

这是一种原理较为简单的迭代器失效。就是在序列式容器中,由于插入/删除数据,导致迭代器所指的内容发生改变,而编写代码者没有即使发现该问题而导致的迭代器失效。

“野指针”类型的迭代器失效

下面我们看这样一段代码

int main()
{
	vector<int> v = { 1, 2, 3, 4, 5, 6 };
	//查找3迭代器的位置
	vector<int>::iterator pos = find(v.begin(), v.end(), 3);	
	if (pos != v.end())
	{
		v.insert(pos, 10);		//在3之前插入10
	}
	PrintVector(v);
	v.erase(pos);
	PrintVector(v);
	return 0;
}

这段代码与上一个代码类似,但是在执行时却发生了报错
在这里插入图片描述
jjfiah我们很容易注意到vector erase iterator outside range这段文字。内容含义是,vector在erase时,出现了越界错误。那么为什么会出现这种错误呢?
在这里插入图片描述

总结

在对序列式容器进行增删数据时,可能会发生容器的增容/缩容,或者越界操作时。就会涉及开辟新的空间,释放旧的空间或者越界访问。这时就会使迭代器指向一块未知的空间,就会发生迭代器失效。

两种迭代器失效合在一起的例子

jjfiah首先先来看下面的代码,代码的目的是删除一串数字中的奇数。

int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	v.push_back(6);
	vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		if (*it % 2 == 0)
			v.erase(it);
		it++;
	}

	return 0;
}

在这里插入图片描述
但是结果发生了内存错误。那么这种错误是怎么发生的呢?我们通过调试+走读代码可以分析出原因。原因如下:
在这里插入图片描述
1、在这里还出现的第一种情况,就是当erase掉it指向的内容后,由于vector是一种顺序型容器,it指向的内容不再是被删除的内容,而是被删除内容之后的内容。所以再次it++就会跳过一个元素。
2、这里it指向了vector之外的内容,就是野指针类型的迭代器失效。

解决方案

在这里插入图片描述
erase的返回值是删除位置的下一个元素的迭代器。所以当我们用it接收返回值时,it就直接是下一个元素的迭代器,就不需要it++等操作了。同时,也不会出现野指针的情况。

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值