vector的迭代器失效问题

1.1 关于迭代器

对于各种数据结构,由于它们的底层实现不同,它们的遍历也不同。例如数组就可以用指针遍历,但链表却不行。而迭代器就像把容器的遍历操作进行了封装,这样在遍历时,就可以针对迭代器进行编程而不用关心容器本身。但是迭代器也可能会失效!

2.1 vector迭代器失效的几种情况

2.1.1 会引起空间本身改变的操作,都可能造成迭代器失效

        用resize、reserveinsertassign、 push_back举例:

#include <iostream>
#include <vector>

int main()
{
    vector<int> v = {0, 1, 2, 3, 4};
    vector<int>:: iterator it = v.begin();
    
    //reserve的作用就是改变空间的大小,可能会引起底层空间的改变
    reserve(10);

    while(it != v.end())
    {
        cout<<*it<<" ";
        ++it;
    }

    cout<<endl;

    return 0;
}

运行结果如下(VS2022):

这里显示是触发了一个assert,错误信息是vector迭代器不兼容,也就意味着当前迭代器失效。

调试一下看看具体原因:

直到第4行代码,it与v.begin()还指向同一块空间

执行完第4行,我们可以看到it与v.begin()已经不一样了,这说明it指向的空间已经销毁,v本身开辟了新的空间,这样继续执行代码,解引用it相对于非法访问。

可是VS这里是出发了一个assert,这是由于VS的编译器检查比较严格,迭代器一旦失效会在非法访问前报错。

resize、insertassign、 push_back操作引起迭代器失效的原因与reserve相同

可以用下面的代码验证:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	vector<int> v = {0, 1, 2, 3, 4};
	vector<int>:: iterator it = v.begin();


	// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变
	 v.reserve(10);


	 // 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容
	// v.resize(20, 6);

	// 插入元素期间,可能会引起扩容,而导致原空间被释放
	// v.insert(v.begin(), 0);
	// v.push_back(10);

	// 给vector重新赋值,可能会引起底层容量改变
	//v.assign(100, 8);

	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	return 0;
}
解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新
赋值即可。

2.1.2 指定位置元素的删除操作 —— erase  

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    int arr[] = { 0, 1, 2, 3 };
    vector<int> v(arr, arr + sizeof(arr) / sizeof(int));

    // 使用find查找3所在位置的iterator
    vector<int>::iterator pos = find(v.begin(), v.end(), 1);

    // 删除pos位置的数据,导致pos迭代器失效。
    v.erase(pos);

    cout << *pos << endl; // 此处会导致非法访问

    return 0;
}

运行结果:

 

这里结果也是一个assert:无法取消引用无效的向量迭代器;

erase并没有改变原来的空间,而是将pos后的元素向pos位置移动,这里报错主要是因为如果删除的是最后一个元素,end()就会前移,pos会指向end(),这个时候如果对pos解引用就会非法访问。VS检查严格,认为删除了元素,迭代器就失效.

如何解决这个问题?

查看一下erase的定义

我们发现erase会返回被删除元素的下一个元素的位置,因此

在使用前,对迭代器重新赋值即可
pos = v.erase(pos);

 

 

 

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值