有关vector模拟实现中迭代器失效问题

1.迭代器失效是什么及原因

迭代器失效是指:如果失效就不能再使用这个迭代器,如果使用了,结果就是未定义的
原因:迭代器失效的主要原因是因为野指针,也可能是因为迭代器的意义改变了

2.insert导致迭代器失效

		void insert(iterator pos, const T& x)
		{
			assert(pos >= _start);
			assert(pos <= _finish);

			if (_finish == _endofstorage)
			{
				//size_t len = pos - _start;//迭代器失效第一种:扩容引起的,野指针
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				//pos = _start + len;
			}

			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;
		}

看下面的测试用例

在这里插入图片描述
第一次头插,请注意那个pos在这里插入图片描述
第二次头插后,_start那几个都变了,pos没有变,这是因为发生了扩容,但是pos迭代器指向的还是那个老空间的位置,所以变成了野指针,发生了错误。
在这里插入图片描述

让我们来看reserve

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t sz = size();
				T* tmp = new T[n];//开辟新空间
				if (_start)
				{
					memcpy(tmp, _start, sizeof(T) * sz);//拷贝原空间数据
					delete[] _start;//释放
				}
				_start = tmp;//变为新空间
				_finish = _start + sz;

				_endofstorage = _start + n;
			}
		}

在这里插入图片描述
针对这种情况,我们可以扩容后重新设置pos指向

		void insert(iterator pos, const T& x)
		{
			assert(pos >= _start);
			assert(pos <= _finish);

			if (_finish == _endofstorage)
			{
				size_t len = pos - _start;//迭代器失效第一种:扩容引起的,野指针
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;//扩容后重新设置pos指向
			}

			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;
		}

提出第二个问题,下面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);
		v.push_back(6);
		v.push_back(7);
		v.push_back(8);
		vector<int>::iterator it = find(v.begin(), v.end(), 1);
		if (it != v.end()) {
			v.insert(it, 2);
		}
		for (auto e : v) {
			cout << e << " ";
		}
		cout << endl;

答案是不可以的
————因为pos是形参,函数内形参的改变对外面的实参没有影响,调整了pos不代表外面实参it也会调整。
即使编译器没有报错,也不要继续使用

3.erase引发的迭代器失效

看下面清除vector中的偶数

	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	std::vector<int>::iterator it = v.begin();
	while (it != v.end()) 
	{
		if ((*it) % 2 == 0)//清除偶数
		{
			v.erase(it);
		}
		++it;
	}
	for (auto e : v) {
		cout << e << " ";
	}
	cout << endl;

会直接报错,因为在这里插入图片描述
而且当删除(获取增加)it位置的元素时,导致it后面的迭代器全部失效。因此多次调用erase insert导致崩溃

vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	std::vector<int>::iterator it = v.begin();
	while (it != v.end()) {
		if ((*it) % 2 == 0) {
			it = v.erase(it);//erase后更新一次
		}
		else
		{
		  ++it;
		}
	}
	for (auto e : v) {
		cout << e << " ";
	}
	cout << endl;
		iterator erase(iterator pos)//返回被删除位置的下一个位置
		{
			assert(pos < _finish);
			assert(pos >= _start);

			iterator it = pos + 1;
			while (it < _finish)
			{
				*(it - 1) = *it;
				++it;
			}
			--_finish;

			return pos;
		}
		//结论:insert和erase以后迭代器都失效了,不能再访问

4.总结

1 当容器调用erase时,当前位置到容器末尾元素的所有的迭代器全部失效
2 当容器调用insert时,当前位置到容器末尾元素的所有的迭代器全部失效;
3 当容器调用insert时,如果引起容器内存扩容,原来容器的所有的迭代器就全部失效

解决办法:
进行更新操作:erase(insert)后会返回指向下一个元素的迭代器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值