C++常用迭代器失效

目录

一、引言

二、迭代器失效的概念

三、常见的迭代器失效场景(这里使用Visual Studio 2019)

1.场景1:在实现vector的insert中

错误代码:

发现问题:

改进代码:

2.场景2:在vs下的强制更新迭代器

不知对错代码:

发现问题:

改进代码:

四、总结


一、引言

在 C++ 编程中,迭代器是访问容器元素的重要工具,它为我们提供了统一的遍历方式。然而,迭代器在某些情况下会失效,这可能导致程序出现难以调试的错误。理解迭代器失效的原因和机制,对于编写健壮的 C++ 代码至关重要。本文将深入探讨 C++ 中迭代器失效的各种情况,并提供相应的应对策略。

二、迭代器失效的概念

迭代器失效是指迭代器所指向的元素或位置在某些操作之后变得无效,此时再使用该迭代器进行操作(如解引用 * 或递增 ++ 等)就会导致未定义行为。简单来说,原本指向有效元素的迭代器,由于容器的某些操作,不再指向预期的有效位置。

三、常见的迭代器失效场景(这里使用Visual Studio 2019)

1.场景1:在实现vector的insert中

错误代码:

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

	if (_finish == _end_of_storage)
	{
		reserve(capacity() == 0 ? 4 : capacity() * 2);
	}
	auto it = _finish - 1;
	while (it >= pos)
	{
		*(it + 1) = *it;
		it--;
	}
	*pos = x;
	++_finish;
}

大家可以思考一下关于pos指向位置扩容后start的关系

reseve的实现代码:

void reserve(size_t n)
{
	if (n > capacity())
	{
		T* tmp = new T[n + 1];
		/*memcpy(tmp, _start, sizeof(T) * size());*/
		for (size_t i = 0; i < size(); i++)
		{
			tmp[i] = _start[i];
		}
		_finish = tmp + size();
		delete[] _start;//释放前地址
		_start = tmp;
		_end_of_storage = _start + n;
	}
}

发现问题:

观察后发现在reseve扩容后是在其他地方开辟一个新的空间

在这里以看见pos如果没有刷新pos和新更新的start指向的根本不是一个东西而原pos已经被扩容给释放从而导致内存泄漏

改进代码:

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

	if (_finish == _end_of_storage)
	{
		size_t oldsize = pos - _start;//先记住pos指向start的位置在更新
		reserve(capacity() == 0 ? 4 : capacity() * 2);
		pos = _start + oldsize;
	}
	auto it = _finish - 1;
	while (it >= pos)
	{
    	*(it + 1) = *it;
		it--;
	}
	*pos = x;
	++_finish;
}

2.场景2:在vs下的强制更新迭代器

在这个我们引入一道题目以便更好理解:

我们要实现删除所有的偶数

大家肯定会一秒秒杀实现如图:

不知对错代码:

auto it = v.begin();
while (it != v.end())
{
	if (*it % 2 == 0)
	{
    	 v.erase(it);
	}
	else
	{
		it++;
	}
}
void erase(iterator pos)
{
	assert(pos >= _start);
	assert(pos < _finish);


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

	_finish--;

}

如果只是这样那未免在简单

在vs下他会报错:

发现问题:

vs对迭代器的检查更加严格,如果你用其他编译器可能不会报错比如Linux

改进代码:

auto it = v.begin();
while (it != v.end())
{
	if (*it % 2 == 0)
	{
	    it = v.erase(it);
	}
	else
	{
		it++;
	}
}
iterator erase(iterator pos)
{
	assert(pos >= _start);
	assert(pos < _finish);


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

	_finish--;
	return pos;
}

 添加返回值指向后边一个的地址在返回,it在外接收这样就实现了迭代器的更新

四、总结

迭代器失效是 C++ 编程中需要特别注意的问题,不同容器在插入、删除等操作时对迭代器的影响各不相同。通过深入理解迭代器失效的原因和机制,并采用合适的应对策略,我们可以避免因迭代器失效导致的程序错误,编写出更加健壮和可靠的 C++ 代码。希望本文能帮助大家更好地处理迭代器失效的情况,提升 C++ 编程的能力。

以上是一篇关于 C++ 迭代器失效的博客文章,你可以根据实际需求进行修改和完善。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值