• C++ STL迭代器失效问题


    1. 问题背景

    在STL里面的容器往往封装了迭代器。迭代器能让人很方便的拿到容器里面的元素进行操作。然而,在不同结构的容器中,删除一个迭代器可能会引发迭代器失效的问题。下面针对不同的容器类型做一下总结。

    太长不看版本:

    1. 对于数组型容器(vector、deque),删除一个迭代器会迫使该迭代器后面的元素往前移动,因此删除的迭代器之后的所有迭代器都会失效。但是在使用erase函数删除迭代器之后会返回下一个有效的迭代器,拿这个迭代器更新即可。

    2. 对于关联式容器(set、map、multiset、multimap),删除一个迭代器只会导致当前的迭代器失效,后面的迭代器可以正常使用。因此,使用erase 得到下一个迭代器或者是使用erase(it++)均可以更新迭代器。

    3. 对于 链表型容器(List),删除一个迭代器只会导致当前的迭代器失效,后面的迭代器可以正常使用。因此,使用erase 得到下一个迭代器或者是使用erase(it++)均可以更新迭代器。

    以下是迭代器失效的场景和解决方法。

    2. 数组型容器(vector、deque)

    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    
    void insert(vector<int>& nums) {
    	for (int i = 0; i < 10; ++i) {
    		nums.push_back(i);
    	}
    }
    
    int main() {
    	vector<int> nums;
    	insert(nums);
    
    	for (auto it = nums.begin(); it != nums.end(); ++it) {
    		if (*it < 3) {
    			nums.erase(it);
    		}
    	}
    	cout << "-----------------------" << endl;
    	for (auto it = nums.begin(); it != nums.end(); ++it) {
    		cout << *it << " " << endl;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在删除后迭代器失效:
    在这里插入图片描述

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    
    void insert(vector<int>& nums) {
    	for (int i = 0; i < 10; ++i) {
    		nums.push_back(i);
    	}
    }
    
    int main() {
    	vector<int> nums;
    	insert(nums);
    
    	/*
    	迭代器失效的错误使用:
    	for (auto it = nums.begin(); it != nums.end(); ++it) {
    		if (*it < 3) {
    			nums.erase(it);
    		}
    	}
    	*/
    	for (auto it = nums.begin(); it != nums.end();) {
    		if (*it < 3) {
    			it = nums.erase(it);
    		} else {
    			++it;
    		}
    	}
    	cout << "-----------------------" << endl;
    	for (auto it = nums.begin(); it != nums.end(); ++it) {
    		cout << *it << " " << endl;
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    迭代器正确的更新方式:

    在这里插入图片描述

    这里由于erase函数在调用之后会返回下一个迭代器,因此不用++,相当于自动移动到下一个迭代器了。

    3. 关联式容器(set、map、multiset、multimap

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    void insert(set<int>& hash) {
    	for (int i = 0; i < 10; ++i) {
    		hash.insert(i);
    	}
    }
    
    int main() {
    	set<int> hash;
    	insert(hash);
    
    	for (auto it = hash.begin(); it != hash.end(); ++it) {
    		if (*it < 3) {
    			hash.erase(it);
    		}
    	}
    	for (auto it = hash.begin(); it != hash.end(); ++it) {
    		cout << *it << " " << endl;
    	}
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在这里插入图片描述

    正确的使用方式:

    在这里插入图片描述

    4. 链表型容器(List)

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    void insert(list<int>& Lst) {
    	for (int i = 0; i < 10; ++i) {
    		Lst.push_back(i);
    	}
    }
    
    int main() {
    	list<int> Lst;
    	insert(Lst);
    
    	for (auto it = Lst.begin(); it != Lst.end(); ++it) {
    		if (*it < 3) {
    			Lst.erase(it);
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    正确的使用方式:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    
    void insert(list<int>& Lst) {
    	for (int i = 0; i < 10; ++i) {
    		Lst.push_back(i);
    	}
    }
    
    int main() {
    	list<int> Lst;
    	insert(Lst);
    
    	//for (auto it = Lst.begin(); it != Lst.end(); ++it) {
    	//	if (*it < 3) {
    	//		Lst.erase(it);
    	//	}
    	//}
    
    	for (auto it = Lst.begin(); it != Lst.end();) {
    		if (*it < 3) {
    			it = Lst.erase(it);
    		} else {
    			++it;
    		}
    	}
    
    	for (auto it = Lst.begin(); it != Lst.end(); ++it) {
    		cout << *it << " " << endl;
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    运行结果:

    在这里插入图片描述

  • 相关阅读:
    k8s单master集群部署完整流程及坑点总结(docker)
    mysql 插入sql语句,把当前时间格式话到时分秒 yyyy-MM-dd
    实现常驻任务除了避免昙花线程,还需要避免重返线程池
    基于SpringBoot的花店销售网站
    禁止瘟疫清零计划 Project Zero与VR一起启动
    说一说:ThreadLocal 、CallContext 、AsyncLocal
    pdf文档转word文档
    XSS进阶之CSP绕过
    利用函数指针数组写计算器(转移表)
    想搞清楚API网关到底是什么?请看这篇
  • 原文地址:https://blog.csdn.net/zsiming/article/details/126879980