vector迭代器失效分析

1.迭代器简介

迭代器(iterator)是STL库的一大组件,它可以让我们更为便利的对容器中的元素进行操作。从使用层面上讲,它的操作十分类似于指针。例如我们可以使用解引用操作,取得迭代器位置的元素。或者是自增操作,让迭代器指向下一个元素。

在vector容器中,迭代器的底层实际就是指针变量。因为vector本身在物理层面就是线性结构,所以可以很好的和指针的操作兼容。

但是,我们在使用迭代器时,常常会遇到迭代器失效的情况。一旦迭代器失效,就可能出现各种意想不到的错误,下面,我们就来分析迭代器失效的原因,以及迭代器失效的解决办法。

2.insert操作导致的迭代器失效

我们在使用insert函数对vector容器进行操作时,需要进行如下调用:

iterator insert (iterator position, const value_type& val);

而迭代器失效就是指传入的position迭代器在经过insert操作后变得不可用。

举个例子:

int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);//v有三个元素 1,2,3

	vector<int>::iterator it = find(v.begin(),v.end(),3);
    //找到3并用迭代器it记录该位置

	v.insert(it, 8);//在3的位置插入一个8
	cout << *it << endl;//输出it位置的元素
	return 0;
}

运行上面这段代码,我们会发现程序崩溃了。这是为什么呢?

因为在insert时,vector可能需要进行扩容,而扩容的本质是new一块新的空间,再将数据迁移过去。而我们知道,迭代器的本质是指针,而插入后,若vector扩容,则原有的数据被释放,指向原有数据的迭代器就成了野指针,所以迭代器失效了。

而解决的办法很简单,insert函数提供了返回值,这个返回值是指向插入之后的val的迭代器。我们只需要保存返回的迭代器,并使用这个新的迭代器即可。

另外,插入操作会导致所有的迭代器失效,因为所有的数据都被迁移,原空间的所有迭代器都成了野指针。

3.erase操作导致的迭代器失效

使用erase函数删除指定迭代器位置的元素,需要进行如下调用:

iterator erase (iterator position);

下面我们用一个例子来说明erase产生的迭代器失效:

int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(1);
	v.push_back(1);
	v.push_back(1); //此时v的元素为 1,1,1,1
	vector<int>::iterator it0 = v.begin();
	vector<int>::iterator it1 = v.begin() + 1;
	vector<int>::iterator it2 = v.begin() + 2;
	vector<int>::iterator it3 = v.begin() + 3;//四个迭代器分别指向下标为0 1 2 3的元素
	v.erase(it2);//erase掉it2迭代器位置的元素
	cout << *it0 << endl;
	cout << *it1 << endl;
	cout << *it2 << endl;
	cout << *it3 << endl;//对四个迭代器指向的元素进行输出
	return 0;
}

我们逐语句进行调试,会发现,it0和it1的值是可以打出来的,而到了it2,程序就会崩溃。

那么,这是为什么呢?其实,在erase后,VS编译器会判定迭代器失效,因为迭代器位置的元素被删除后,不再指向删除前的元素,所以迭代器失效了。故程序运行到输出it2位置,就崩溃了。

int main()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(1);
	v.push_back(1);
	v.push_back(1); 
	vector<int>::iterator it0 = v.begin();
	vector<int>::iterator it1 = v.begin() + 1;
	vector<int>::iterator it2 = v.begin() + 2;
	vector<int>::iterator it3 = v.begin() + 3;
	v.erase(it2);
	cout << *it0 << endl;
	cout << *it1 << endl;//q去掉了删除it2位置元素的操作
	cout << *it3 << endl;
	return 0;
}

接着,我们把输出it2的语句删除,但是我们运行到输出it3所指向的元素时,程序仍然崩溃了。这是因为,删除操作后,由于删除位置后面的数据都要向前挪一位,导致了删除位置后面的迭代器所指向的元素都发生了变化,所以处于it2位置之后的it3,也在所难免的失效了。

解决erase操作导致的迭代器失效的办法也很简单,erase同样会返回一个迭代器,这个迭代器指向了在erase操作前,被删除元素的下一个元素的新位置。所以,我们进行erase操作后,直接使用这个返回的迭代器即可。

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
vector迭代器失效的情况包括插入(insert)和删除(erase)操作。当进行插入操作时,如果插入元素导致内存重新分配,已经获取的迭代器可能失效。因为重新分配后,原来的内存空间被释放,迭代器指向的位置就变得无效。同样,当进行删除操作时,被删除的元素之后的所有元素都向前移动,导致原本有效的迭代器指向错误的元素,从而失效。 举个例子,当使用erase操作删除一个元素后,被删除元素之后的所有元素向前移动,导致原本指向这些元素的迭代器指向了错误的位置,从而失效。比如在示例代码中,当使用v.erase(it2)删除it2位置的元素后,it3原本指向下标为3的元素,但由于删除操作,它现在指向了下标为2的元素,导致输出时发生错误。 因此,要避免迭代器失效,可以采取以下措施: 1. 在进行插入或删除操作后,重新获取迭代器,而不是继续使用之前的迭代器。 2. 使用索引而不是迭代器操作元素,因为索引不受到元素的插入或删除操作的影响。 3. 在进行插入或删除操作之前,先判断迭代器是否有效,可以使用迭代器的成员函数进行判断,例如vector::begin()和vector::end()。 综上所述,vector迭代器失效的情况主要包括插入和删除操作,为了避免迭代器失效,可以重新获取迭代器、使用索引操作元素或进行有效性判断。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [vector迭代器失效分析](https://blog.csdn.net/LiangXiay/article/details/123468285)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值