迭代器失效(附案例详解)
Posted xiao zhou
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了迭代器失效(附案例详解)相关的知识,希望对你有一定的参考价值。
本文将使用具体案例来详细解读迭代器失效的各种原因
迭代器指向内容意义改变
下面我们看一段代码
int main()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
//查找3迭代器的位置
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
if (pos != v.end())
{
v.insert(pos, 10); //在3之前插入10
}
PrintVector(v);
v.erase(pos);
PrintVector(v);
return 0;
}
在3之前插入10后,我们又想将pos位置的3删除掉。
可是问题来了,这样的代码真的可以按照我们的想法进行吗?在我们执行代码后,我们发现并没有发生我们所预期的结果
jjfiah很明显,这样的代码是错误的,而这里错误的原因就是迭代器意义改变的一种迭代器失效。
jjfiah那么具体的错误是如何发生的呢?答案就是,在我们进行insert后,pos将不会再指向3,而是指向刚刚插入的10。
jjfiah假如说,插入之前pos的值是0x11223344,在插入10后,由于3-5这些数字要往后挪动,于是10就被放置在原先3的位置,而pos并没有随着3位置的改变而改变,因此,pos指向的就是10。pos代表的含义就变了
总结
这是一种原理较为简单的迭代器失效。就是在序列式容器中,由于插入/删除数据,导致迭代器所指的内容发生改变,而编写代码者没有即使发现该问题而导致的迭代器失效。
“野指针”类型的迭代器失效
下面我们看这样一段代码
int main()
{
vector<int> v = { 1, 2, 3, 4, 5, 6 };
//查找3迭代器的位置
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
if (pos != v.end())
{
v.insert(pos, 10); //在3之前插入10
}
PrintVector(v);
v.erase(pos);
PrintVector(v);
return 0;
}
这段代码与上一个代码类似,但是在执行时却发生了报错
jjfiah我们很容易注意到vector erase iterator outside range这段文字。内容含义是,vector在erase时,出现了越界错误。那么为什么会出现这种错误呢?
总结
在对序列式容器进行增删数据时,可能会发生容器的增容/缩容,或者越界操作时。就会涉及开辟新的空间,释放旧的空间或者越界访问。这时就会使迭代器指向一块未知的空间,就会发生迭代器失效。
两种迭代器失效合在一起的例子
jjfiah首先先来看下面的代码,代码的目的是删除一串数字中的奇数。
int main()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
vector<int>::iterator it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
v.erase(it);
it++;
}
return 0;
}
但是结果发生了内存错误。那么这种错误是怎么发生的呢?我们通过调试+走读代码可以分析出原因。原因如下:
1、在这里还出现的第一种情况,就是当erase掉it指向的内容后,由于vector是一种顺序型容器,it指向的内容不再是被删除的内容,而是被删除内容之后的内容。所以再次it++就会跳过一个元素。
2、这里it指向了vector之外的内容,就是野指针类型的迭代器失效。
解决方案
erase的返回值是删除位置的下一个元素的迭代器。所以当我们用it接收返回值时,it就直接是下一个元素的迭代器,就不需要it++等操作了。同时,也不会出现野指针的情况。
以上是关于迭代器失效(附案例详解)的主要内容,如果未能解决你的问题,请参考以下文章
[C/C++]详解STL容器3--list的功能和模拟实现(迭代器失效问题)
[C/C++]详解STL容器2--vector的功能和模拟实现(迭代器失效,memcpy拷贝问题)