在C++中迭代器失效是个常见的问题,通常有两种情况的迭代器失效问题
1.容器扩容,迭代器失效
例1:模拟实现vector容器的insert函数时,函数原型为
void insert(iterator position, const T& val)
如果容器发生扩容,则需要开辟新空间,将旧空间数据拷贝到新空间中,最后销毁旧空间。而迭代器position始终没有改变,仍然指向旧空间中的某个位置,从而导致程序bug。
如何解决?如果容器发生扩容,则更新迭代器。
//insert
void insert(iterator position, const T& val)
{
assert(position <= _finish);
assert(position >= _start);
size_t len = position - _start;//2.迭代器失效问题,如果发生扩容,position还是指向原来的空间位置,是野指针,需要更新position的位置
//扩容
if (size() == capacity())
{
reserve(capacity() == 0 ? 4 : 2 * capacity());
}
position = _start + len;//更新position位置
//挪动数据
iterator end = _finish;
while (end > position)
{
*end = *(end - 1);
--end;
}
//插入数据
*position = val;
++_finish;
}
例2:容器扩容,迭代器失效,具体要看容器的扩容方式,只有当容器扩容时迭代器才会失效。也就是说正常push数据时迭代器可能失效,因此我们要及时更新迭代器。
如果容器是二倍扩容,初始时空间为4,那么当插入第5个数据时,容器需要扩容,迭代器即失效
迭代器it已经失效,未更新不能继续使用(VS编译器下无论迭代器是否失效,只要未更新就不能使用)
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
auto it = v.begin() + 3;
v.insert(it, 9);
cout << *it << endl;
vector容器在编写insert函数时设置的函数返回值为迭代器指向当前插入位置,目的就是为了提供更新迭代器的接口,防止迭代器失效
正确修改:更新迭代器it再使用
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
auto it = v.begin() + 3;
it= v.insert(it, 9);
cout << *it << endl;
2.数据变动,迭代器失效
例如利用迭代器删除vector容器中的偶数(数据为:0 2 4 6 8 9 )
it指数据0位置,0为偶数,删除该数据,此时后面所有数据前移,数据0位置数据被2替代,此时迭代器it++,指数据4位置,跳过了数据2,因而程序出现bug
vector<int>::iterator it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
v.erase(it);
++it;
}
其实当erase删除数据时,此时迭代器就已经失效了,不能进行++(VS2022编译器下直接报错)
如何解决?每次删除数据即更新迭代器
vector<int>::iterator it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
it = v.erase(it);
else
++it;
}
综上所述,解决迭代器失效问题的有效方法就是:及时更新迭代器