stl中vector中erase后迭代器为啥会失效
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了stl中vector中erase后迭代器为啥会失效相关的知识,希望对你有一定的参考价值。
在对容器进行改变结构性的操作后,比如删除插入等操作..
原来得到的迭代器指针会出现某些错误
注意这里向量容器因用动态数组实现的,所以当你删除或者插入时候,元素位置发生变动,这时候你之前得到的迭代器尾或者头,不指向了不合法的位置,
保险的做法是在做着先改变以后在重新返回一次起始迭代器和结束迭代器
以上个人说法,不严谨的请自行过滤 参考技术A gcc
4.4是符合iso2003标准的编译器,而vc6不符合。——因该以gcc下能运行为标准,而非旧版vc
标准下v.erase输入参数是迭代指针,而&v[1]是一个int地址
补救做法,强制转换
1、v.erase(
static_cast
::iterator>(&v[1])
);
2、v.erase(
(vector
::iterator)(&v[1])
);
标准做法,迭代器操作
3、v.erase(
v.begin()+1
);
ps:另外for循环中的v[0]也因该是v[i]
面试中常被问到STL迭代器失效问题
STL容器中迭代器失效的场景:
以vector为例进行分析
vector进行数据插入
- 如果空间充足那组,插入数据后,原有数据向后移动,导致迭代器失效
- 如果空间不足,插入新数据需要扩容,则发生拷贝,导致迭代器失效
void reverse(size_t n)
{
if (n > capacity())
{
//保存有效元素个数
size_t sz = size();
//申请空间
T* tmp = new T[n];
//拷贝原有空间
if (_start)
{
//memcpy(tmp, _start, sizeof(T)*size());//内置类型 进行深拷贝 如果自定义类型 进行浅拷贝
for (size_t i = 0; i < sz; i++)
{
tmp[i] = _start[i];//调用赋值运算符重载函数进行深拷贝,目的是 保证类型完成深拷贝(比如自定义string类型)
}
delete[]_start;
}
//更新
_start = tmp;
//_finish=_start+size();//由于start更新 导致size()出问题 finish丢失,需要提前记录size ,重新找到finish指向
_finish = _start + sz;
_endofstorage = _start + n;
}
}
void insert(iterator pos, const T& val)
{
//检查位置
assert( pos<=end()&&pos>=begin());
//检查容量
if (_finish == _endofstorage)
{
//记录偏移量
size_t offset = pos - _start;
size_t newcap = _endofstorage == nullptr ? 1 : 2 * capacity();
reverse(newcap);//增容空间拷贝导致迭代器失效 pos位置丢失
pos = _start + offset;//增容之后 更新pos位置
}
//移动元素
iterator it = end();
while (it>pos)
{
*it = *(it - 1);
it--;
}
*pos = val;
//更新
_finish++;
}
解决插入后迭代器失效的方法就是如果需要扩容就在插入前记录当前插入位置距起始位置的偏移量,扩容之后,根据偏移量更新插入位置,同时移动元素从后往前遍历,移动更新迭代器指向位置
vector进行数据删除
给一个int类型的vector容器增加20个整数,然后删除里面所有的偶数
vector<int> vec;
for(int i=0; i<20; ++i)
{
vec.push_back(rand()%100);
}
vector<int>::iterator it = vec.begin();
while(it!=vec.end())
{
if(*it % 2 == 0)
{
vec.erase(it);
}
else
{
++it;
}
}
上述代码中,删除第一个偶数后,起始位置到当前删除位置的迭代器都是正常的,之后的失效
解决方法如下:
vector<int> vec;
for (int i = 0; i < 20; ++i)
{
vec.push_back(rand() % 100);
}
vector<int>::iterator it = vec.begin();
while (it != vec.end())
{
if (*it % 2 == 0)
{
it = vec.erase(it);
}
else
{
++it;
}
}
return 0;
由于erase返回删除位置的下一位置,每次删除重新对迭代器赋值,更新迭代器位置指向,此时已经指向下一位置,所以不需要迭代器后移,否则会跳过部分数据,这个点经常出现在一些选择题代码分析上哦
以上是关于stl中vector中erase后迭代器为啥会失效的主要内容,如果未能解决你的问题,请参考以下文章