deque 迭代器失效的问题详解

    今天在看STL源码的时候,无意写了如下的代码,发现程序崩溃了:

<span style="font-size:14px;">    deque<int>::iterator iter=d.begin();
    d.insert(iter,5); 
    d.insert(iter,6); //崩溃,迭代器失效了

</span>
之前一直没有留意这个问题,后来结合源码和查找资料,得到如下的结论:

插入操作:

1、在队前或队后插入元素时(push_back(),push_front()),由于可能缓冲区的空间不够,需要增加map中控器,而中控器的个数也不够,所以新开辟更大的空间来容纳中控器,所以可能会使迭代器失效;但指针、引用仍有效,因为缓冲区已有的元素没有重新分配内存。

2、在队列其他位置插入元素时,由于会造成缓冲区的一些元素的移动(源码中执行copy()来移动数据),所以肯定会造成迭代器的失效;并且指针、引用都会失效

删除操作:

1、删除队头或队尾的元素时,由于只是对当前的元素进行操作,所以其他元素的迭代器不会受到影响,所以一定不会失效,而且指针和引用也都不会失效;

2、删除其他位置的元素时,也会造成元素的移动,所以其他元素的迭代器指针和引用都会失效。

测试代码:

deque<int>::iterator iter=d.begin();
d.push_back(10);
cout<<*iter<<endl;

在vs2012中运行时,程序立即崩溃:

而且,不管有没有出现重新分配map中控器,往deque中插入元素都会导致迭代器的失效,所以,插入一个元素后,iter迭代器已经失效了,所以再对失效的迭代器取值会导致程序崩溃,出现如上错误,不知道其他的编译器对这种情况是如何处理的。

查找资料为:

vector迭代器的几种失效的情况:
1.当插入(push_back)一个元素后,end操作返回的迭代器肯定失效。
2.当插入(push_back)一个元素后,capacity返回值与没有插入元素之前相比有改变,则需要重新加载整个容器,此时first和end操作返回的迭代器都会失效。
3.当进行删除操作(erase,pop_back)后,指向删除点的迭代器全部失效;指向删除点后面的元素的迭代器也将全部失效。

deque迭代器的失效情况: ,在C++Primer一书中是这样限定的,
1.在deque容器首部或者尾部插入元素不会使得任何迭代器失效。//通过vs2012测试不管前端插入还是后端插入,都会使迭代器 失效
2.在其首部或尾部删除元素则只会使指向被删除元素的迭代器失效。
3.在deque容器的任何其他位置的插入和删除操作将使指向该容器元素的所有迭代器失效。

再次测试:

deque<int>::iterator iter=d.begin();
d.pop_back();
cout<<*iter<<endl;

上面代码可以顺利通过测试,说明队尾弹出元素并不会使迭代器失效(当然删除的那个元素的迭代器肯定会失效)。
所以,为了避免程序因为迭代器的失效而程序崩溃,所以尤其在对元素进行插入和删除的操作时一定要考虑迭代器的失效问题,上面第一个测试代码的正确版如下:

int main()
{
	int i[10]={1,2,5,3,7,5,2,8,5,9};
	list<int>  l;
	deque<int,allocator<int>> d(i,i+10);
	deque<int>::iterator iter=d.begin();
	iter=d.insert(iter,5);   //插入返回一个插入点的迭代器,重新给iter迭代器赋值就没有问题了。
	iter=d.insert(iter,6);
	cout<<*iter<<endl;  //输出结果为6
}




  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
1. STL的三大件分别是容器、算法和迭代器,它们之间是相互独立、相互配合的关系。容器提供了存储数据的能力,算法提供了对容器中数据的操作能力,迭代器提供了容器中元素的遍历能力。 2. C++指针和STL迭代器都提供了对内存中一段数据的遍历能力,但是它们之间的区别是:指针是原生的语言特性,只能访问数组或指向单个对象的指针,而迭代器STL中的一种抽象对象,可以遍历任意STL容器的元素。另外,迭代器还提供了更多的操作,如自增、自减、解引用等。 3. 函数对象是一种类对象,它可以像函数一样被调用,即可以重载 operator()。定义函数对象有两种方式:一种是定义一个继承自 std::unary_function 或 std::binary_function 的类,另一种是定义一个重载了 operator() 的类。函数对象通常用在算法中,如排序、查找等。 4. STL中的迭代器按照语义功能可以分为输入迭代器、输出迭代器、正向迭代器、双向迭代器和随机访问迭代器。它们在功能上的主要差别是:输入迭代器只能读取容器中的元素,而输出迭代器只能写入容器中的元素,正向迭代器可以向前遍历容器中的元素,双向迭代器可以向前或向后遍历容器中的元素,随机访问迭代器可以随机访问容器中的元素。 5. vector和deque迭代器属于随机访问迭代器,而list的迭代器属于双向迭代器。在访问容器元素时应该注意迭代器失效问题,即在对容器进行插入、删除等操作后,迭代器可能会失效。调用通用算法时也应该注意迭代器的类型和范围,以避免产生未定义的行为。 6. 编译器提示错误的原因是:L1.begin()返回的是list<int>::iterator类型的迭代器,不能直接与数字相加。正确的写法应该是:list<int>::iterator itr = std::next(L1.begin(), 5); 7. 迭代器是容器和算法之间的桥梁,它提供了容器中元素的遍历能力,使得算法可以对容器中的元素进行各种操作。通过迭代器,算法可以遍历容器中的元素,而不需要关心容器中元素的具体类型和存储方式。 8. 迭代器失效的根本原因是容器的结构发生了变化,比如进行了插入、删除等操作。这些操作可能会导致容器中元素的地址、数量、顺序等发生变化,从而使得原先的迭代器无法正确访问容器中的元素。常见的导致迭代器失效的操作包括:插入、删除、排序、去重等。 9. 可以通过表达式b-a来计算区间[a,b)之间的元素个数,但是要求a和b是同一容器对象的迭代器,且这个容器必须是随机访问迭代器。在其他类型的迭代器中,可能不存在“元素个数”的概念,或者无法通过简单的减法计算元素个数。如果容器不是随机访问迭代器,可以通过循环遍历区间,计算元素个数。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值