C++: vector iterator not incrementable,迭代器失效问题

本文探讨了导致迭代器失效的一个常见原因:在遍历vector容器时改变其容量。当vector进行扩容操作时,原有的内存会被释放,迭代器会失效。通过测试用例说明了在插入元素、手动调用shrink_to_fit()以及使用remove函数时迭代器的行为。理解这一原理需要了解vector的内部实现,包括push_back()和insert()等函数的细节。
摘要由CSDN通过智能技术生成

导致此问题有很多原因,常见的一个原因是将迭代器所指向的元素删除后迭代器失效,而本文要讨论的是另外一个原因:迭代器遍历容器时改变容器大小(capacity)而导致迭代器失效

结论:在进行迭代器遍历容器时,原来的容器不应该再继续压入任何元素了,否则迭代器可能失效。


原理部分

下面我们来以vector为例讨论一下迭代器失效背后的原理,以及什么时候会失效,什么时候正常。

先上结论:vector的迭代器失效的原因是,vector进行了改变容量大小(注意是capacity而非size)的操作,这个时候,会重新申请内存空间,并将原来的元素进行拷贝,这个时候指向原来位置的iterator仍旧指向原来的位置,而这时原来的位置的元素早已在vector扩容操作里被删除了,故此时iterator指向的是一个未知的值,故迭代器失效

下面给出几种情况的测试用例:

  • 刚开始插入元素迭代器有效,之后失效(刚开始capacity大小为3,插入后不用扩容,故刚开始有效)
	vector<int>vec_1{1};
	vec_1.reserve(3);
	for (auto itor = vec_1.begin(); itor != vec_1.end(); ++itor) {
		vec_1.push_back(2);
	}
  • 刚开始容器大小为30,手动调用shrink_to_fit()函数失效(改变了容器大小)
	vector<int>vec_2{ 1, 2, 3};
	vec_2.reserve(30);
	for (auto itor = vec_2.begin(); itor != vec_2.end(); ++itor) {
		vec_2.shrink_to_fit();
	}
  • remove函数不改变容器的大小capacity不会失效
	vector<int>vec_3{ 1, 2, 3 };
	vec_3.reserve(30);
	for (auto itor = vec_3.begin(); itor != vec_3.end(); ++itor) {
		remove(vec_3.begin(), vec_3.end(),1);
	}
	

注意,想要真正理解原理,必须了解vector的实现,下面附上与本问题相关的部分STL源码(GNU2.9版)

 void push_back(const T& x) {
    if (finish != end_of_storage) {
      construct(finish, x);
      ++finish;
    }
    else
      insert_aux(end(), x);
  }
template <class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x) {
  if (finish != end_of_storage) {
    construct(finish, *(finish - 1));
    ++finish;
    T x_copy = x;
    copy_backward(position, finish - 2, finish - 1);
    *position = x_copy;
  }
  else {
    const size_type old_size = size();
    const size_type len = old_size != 0 ? 2 * old_size : 1;
    iterator new_start = data_allocator::allocate(len);
    iterator new_finish = new_start;
    __STL_TRY {
      new_finish = uninitialized_copy(start, position, new_start);
      construct(new_finish, x);
      ++new_finish;
      new_finish = uninitialized_copy(position, finish, new_finish);
    }

#       ifdef  __STL_USE_EXCEPTIONS 
    catch(...) {
      destroy(new_start, new_finish); 
      data_allocator::deallocate(new_start, len);
      throw;
    }
#       endif /* __STL_USE_EXCEPTIONS */
    destroy(begin(), end());
    deallocate();
    start = new_start;
    finish = new_finish;
    end_of_storage = new_start + len;
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流年剑客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值