关于list循环删除元素,迭代器失效的问题

本文介绍了一种在C++中如何安全地从list容器中删除元素的方法,并提供了具体的代码实现。通过保存当前迭代器的方式,确保了删除操作过程中迭代器的有效性。
部署运行你感兴趣的模型镜像

问题的关键是:在删除元素之前,将当前迭代器保存下来。当然,这里仅支持list,因为list的链式的删除一个元素,前面的指针指向下一个元素,vector和queue就不好办了,它们或者是线性的或者是半线性半链式,迭代器会失效

#include<iostream>
#include<list>
using namespace std;
int main()
{
	list<int *> l;
	for(int i=1;i<=100;i++)
	{


		int* temp=new int;
		*temp=i;
		l.push_back(temp);
	}
	list<int *>::iterator it=l.begin();
	list<int *>::iterator ittemp=l.begin();
	for(;it!=l.end();++it)
	{
		cout<<*(*it)<<endl;


	}
	it=l.begin();
	ittemp=l.begin();
	for(;it!=l.end();)
	{
		ittemp=it;
		++it;
		delete (*ittemp);
		l.erase(ittemp);


	}
	cout<<l.size()<<endl;
	return 0;


}

关注微信公众号,获取更多资料


您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<think>### C++ List容器的迭代器失效问题 在C++标准库中,`std::list`(双向链表)的迭代器失效规则与其他顺序容器(如vector/deque)有**本质区别**,核心结论是: #### 迭代器失效规则 1. **插入操作(insert/push_back/push_front)**: - **不会**使任何迭代器失效(包括end迭代器) - 新元素插入后,已有迭代器仍指向原元素 2. **删除操作(erase/pop_back/pop_front)**: - **只有被删除元素迭代器失效** - 其他迭代器(包括指向未删除元素迭代器)保持有效 3. **拼接操作(splice)**: - 在同一个list内移动元素迭代器仍有效(指向同一元素) - 在不同list间转移元素:源容器的迭代器失效,目标容器迭代器不受影响 4. **修改操作(assign/clear/resize)**: - `clear()`:使所有迭代器失效 - `resize()`:新增元素的部分不影响已有迭代器;缩减时被删除元素迭代器失效 - `assign()`:等价于先`clear()`后插入,所有原迭代器失效 #### 示例代码演示 ```cpp #include <list> #include <iostream> using namespace std; int main() { list<int> lst = {1, 2, 3, 4}; // 示例1:插入不影响迭代器 auto it = lst.begin(); advance(it, 2); // 指向3 lst.insert(it, 10); // 在3前插入10 cout << *it << endl; // 输出3(仍有效) // 示例2:删除仅使被删迭代器失效 it = lst.begin(); // 指向1 auto it2 = next(it); // 指向2 lst.erase(it); // cout << *it << endl; // 错误!it已失效 cout << *it2 << endl; // 输出2(仍有效) // 示例3:splice转移元素 list<int> lst2 = {5, 6}; it = lst2.begin(); lst.splice(lst.end(), lst2); // 将lst2所有元素移到lst末尾 // cout << *it << endl; // 错误!it(原指向lst2元素)已失效 it = prev(lst.end()); // 重新获取(指向6) cout << *it << endl; // 输出6 } ``` #### 与vector的对比 | 操作 | std::list | std::vector | |--------------|-------------------------------|-------------------------------| | 插入元素 | **不失效**(除被删迭代器) | 可能失效(容量变化时全失效) | | 删除元素 | 仅被删迭代器失效 | 被删之后所有迭代器失效 | | 尾部追加 | 不失效 | 仅当容量不足重新分配时失效 | | 中间插入 | 不失效 | 插入点之后所有迭代器失效 | #### 最佳实践 1. **安全删除模式**: ```cpp for (auto it = lst.begin(); it != lst.end(); ) { if (*it % 2 == 0) { it = lst.erase(it); // erase返回下一个有效迭代器 } else { ++it; } } ``` 2. **避免跨操作保存迭代器**: - 当容器可能被修改时,避免长期保存迭代器 3. **范围for循环安全**: ```cpp for (auto& x : lst) { // 安全:不直接操作迭代器 // 但循环内不能执行lst.erase()等操作 } ``` 4. **失效检测(调试辅助)**: ```cpp #ifdef _DEBUG #define CHECK_ITER(cont, iter) \ if (iter != cont.end() && \ std::find(cont.begin(), cont.end(), *iter) == cont.end()) \ { \ throw std::runtime_error("迭代器失效"); \ } #endif ``` §§相关问题§§ 1. std::vector在哪些操作下会导致迭代器失效? 2. 如何安全地在遍历std::list删除元素? 3. std::forward_list迭代器失效规则与std::list有何不同? 4. 在多线程环境下使用std::list如何保证迭代器安全? 5. C++17引入的std::pmr::list迭代器行为上有区别吗? </think> ### C++ List容器的迭代器失效问题 在C++标准库中,**`std::list`(双向链表)的迭代器具有特殊的失效规则**,与其他顺序容器(如`vector`/`deque`)有显著区别: #### ✅ 不会导致迭代器失效的操作 1. **插入操作** `push_back()`, `push_front()`, `insert()` ```cpp std::list<int> lst{1, 2, 3}; auto it = ++lst.begin(); // 指向2 lst.insert(it, 10); // 在2前插入10 // it仍有效,指向2(新序列:1,10,2,3) ``` 2. **删除操作(非当前迭代器)** `pop_back()`, `pop_front()`, `erase(其他迭代器)` ```cpp std::list<int> lst{1, 2, 3}; auto it1 = lst.begin(); // 指向1 auto it2 = ++lst.begin(); // 指向2 lst.erase(it1); // 删除1 // it2仍有效,指向2(序列变为2,3) ``` 3. **拼接操作(splice)** 同list内移动元素: ```cpp std::list<int> lst{1, 2, 3, 4}; auto it = ++++lst.begin(); // 指向3 lst.splice(lst.begin(), lst, it); // it仍有效,指向3(新序列:3,1,2,4) ``` #### ❌ 导致迭代器失效的操作 1. **删除当前迭代器** ```cpp std::list<int> lst{1, 2, 3}; auto it = lst.begin(); lst.erase(it); // it立即失效! // ++it; // 未定义行为! ``` 2. **清除容器** `clear()`使所有迭代器失效。 3. **不同list间的splice** ```cpp std::list<int> lst1{1}, lst2{2}; auto it = lst2.begin(); lst1.splice(lst1.end(), lst2); // it失效元素已移入lst1) ``` #### 安全操作模式 ```cpp // 安全遍历删除(erase返回下一元素迭代器) for (auto it = lst.begin(); it != lst.end(); ) { if (*it % 2 == 0) { it = lst.erase(it); // 关键:接收返回值 } else { ++it; } } ``` #### 与vector的对比 | 操作 | `std::list` | `std::vector` | |--------------|----------------------------|----------------------------| | 尾部插入 | **不失效** | 容量不足时全失效 | | 中间插入 | **不失效** | 插入点后全失效 | | 删除元素 | **仅被删迭代器失效** | 被删元素后全失效 | | 容器销毁 | 全失效 | 全失效 | #### 重要结论 - **链表结构特性**:`std::list`的节点独立分配内存,增删操作**不涉及内存重分配**。 - **失效边界明确**:仅当迭代器指向的元素删除时,该迭代器失效。 - **范围for循环限制**:循环中直接删除当前元素会引发未定义行为(需改用手动迭代器遍历)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值