关于迭代器失效

vector,内存连续,类似数组,当删除其中一个元素时,后边的每一个元素都要往前移动,导致迭代器失效,所以不能用earse(it++)。vector的earse返回新的迭代器。

map,红黑树,删除时,只是删除的失效,所以可以用earse(iter++),相当于 tmpIter = iter;it++;earse(iter);

顺序容器vector

vector是一个线性顺序机构,连续存储空间,相当于数组,可以自动扩展,可以将其看成动态数组。

早创建一个vector后,会自动在内存中分配一块连续的内存空间,初始空间大小可以预先指定也可以由vectro默认指定,这个大小即capacity ()函数的返回值。当存储的数据超过分配的空间时vector 会重新分配一块内存块,但这样的分配是很耗时的,在重新分配空间时它会做这样的动作:

首先,vector 会申请一块更大的内存块;

然后,将原来的数据拷贝到新的内存块中;

其次,销毁掉原内存块中的对象(调用对象的析构函数);

最后,将原来的内存空间释放掉。

如果vector 保存的数据量很大时,这样的操作一定会导致糟糕的性能(这也是vector 被设计成比较容易拷贝的值类型的原因)。所以说vector 不是在什么情况下性能都好,只有在预先知道它大小的情况下vector 的性能才是最优的。

需要注意的是,一旦引起空间重新配置,之前指向原vector的所有迭代器就都失效了,这一点在工程中容易引起bug。(如何避免

vector迭代器失效:

    vector<int> vec;
	for (int i = 0; i < 5; i++)
	{
		vec.push_back(i);
	}
	for (auto it = vec.begin(); it != vec.end(); it++)
	{
		if (*it == 3)
		{
			vec.erase(it);//此处会发生迭代器失效
		}
	}

迭代器在执行++操作时报错,已经失效的迭代器不能再进行自增运算了。

对于vector,删除当前的iterator会使后面所有元素的iterator都失效,这是因为vector是连续存储的一段空间,eras删除一个元素,后面所有的元素会向前移动一个位置。从而不仅使指向被删除元素的迭代器失效,而且使被删元素之后的所有迭代器失效,所以不能使用erase(iter++)的方式,但是erase的返回值为下一个有效的迭代器所以可以这样使用(千万注意不要把else漏掉):

    vector<int> vec;	
	for (int i = 0; i < 5; i++)
	{
		vec.push_back(i);
	}
	for (auto it = vec.begin(); it != vec.end(); )
	{
		if (*it == 3)
		{
			it = vec.erase(it);//erase的返回值是被删除元素的下一个元素的迭代器
		}
		else
		{
			it++;
		}
	}

关联容器map

map是关联容器,以红黑树或者平衡二叉树组织数据,虽然删除了一个元素,整棵树也会调整,以符合红黑树或者二叉树的规范,但是单个节点在内存中的地址没有变化,变化的是各节点之间的指向关系。

map

    map<int, int> m;
	m[1] = 1;
	m[2] = 2;
	m[3] = 3;
	for (auto iter = m.begin(); iter != m.end(); iter++)
	{
		if (iter->second == 2)
		{
			m.erase(iter);			
		}
	}

m.erase(iter)之后,iter就已经失效了,所以iter无法自增,即iter++就会出bug.

对于关联容器(如map),删除当前的iterator,仅仅会使当前的iterator失效(因为map之类的容器,使用了红黑树来实现,插入、删除一个结点不会对其他结点造成影响)

解决方案,就是在iter失效之前,先自增。erase迭代器只是被删元素的迭代器失效,但是返回值为void,所以要采用erase(iter++)的方式删除迭代器。

修改:

    map<int, int> m;
	m[1] = 1;
	m[2] = 2;
	m[3] = 3;
	for (auto iter = m.begin(); iter != m.end();)
	{
		if (iter->second == 2)
		{
			m.erase(iter++);
            //或者如下:
            /*map<int, int>::iterator tmpIter = iter;
			iter++;
			m.erase(tmpIter);*/
		}
		else
		{
			iter++;
		}
	}

m.erase(iter++);这句话分三步走,先把iter传值到erase里面,然后iter自增,然后执行erase,所以iter在失效前已经自增了。

 

参考:

https://blog.csdn.net/lujiandong1/article/details/49872763 迭代器失效的几种情况总结

https://blog.csdn.net/qq_37964547/article/details/81160505  关于迭代器失效的几种情况

https://blog.csdn.net/codercong/article/details/52065130 c++STL迭代器失效问题

https://blog.csdn.net/w87510255/article/details/79408500     STL 顺序容器,关联容器

https://blog.csdn.net/lhc548453346/article/details/50822294?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control    STL之顺序容器和关联容器总结

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值