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 顺序容器,关联容器