• 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

    运行结果:

    在这里插入图片描述

  • 相关阅读:
    MMFewShot训练与测试流程
    Rust中的结构体
    【明年找到好工作】:面试题打卡第二天
    0038__一文看懂NB-IOT/Lora/Zigbee三大技术的组网方式
    牛客前端宝典——刷题 ##Day11
    Prometheus+Grafana对Mysql实现监控
    Java常用设计模式
    【cartographer_ros】七: 主要配置参数说明
    MapReduce编程:检索特定群体搜索记录和定义分片操作
    python 生成随机字符串(大小写英文字母、数字组成)、生成随机的无重复字符的字符串
  • 原文地址:https://blog.csdn.net/zsiming/article/details/126879980