stl容器循环删除元素总结

程序中有一段代码是关于stl循环删除的内容,大体逻辑如下(实际逻辑要复杂的多,不适合用std::remove系列函数):

int main(int argc, char **argv)
{
	std::vector<int> vec{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	auto it_vec = vec.begin();
	while (it_vec != vec.end()) {
		if (*it_vec % 2 == 0) {
			vec.erase(it_vec++);
			continue;
		}
		++it_vec;
	}

	return 0;
}

尽管平常都是用std::remove系列函数,但印象中上面的代码也没有任何问题的,但是程序一运行却当掉了。原因是每次执行std::vector::erase之后,迭代器是失效,当再次执行it_vec != vc.end()时,程序当掉。具体原因:std::vector,std::string,std::deque等顺序存储的容器,插入删除操作均会是所有容器失效;std::list,std::map,std::set等非顺序存储的容器,执行删除操作仅会是当前迭代器失效,插入操作不会是任何迭代器失效。无论是顺序结构容器,还是非顺序结构容器,删除操作都会返回最后一个被删除元素的后一个迭代器。

因此,对于std::vector,std::string,std::deque而言,正确的循环删除操作如下:

int main(int argc, char **argv)
{
	std::vector<int> vec{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	auto it_vec = vec.begin();
	while (it_vec != vec.end()) {
		if (*it_vec % 2 == 0) {
			it_vec = vec.erase(it_vec);
			continue;
		}
		++it_vec;
	}

	std::string str("school college");
	auto it_str = str.begin();
	while (it_str != str.end()) {
		if (*it_str == 'o') {
			it_str = str.erase(it_str);
			continue;
		}
		++it_str;
	}

	std::deque<int> deq{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	auto it_deq = deq.begin();
	while (it_deq != deq.end()) {
		if (*it_deq % 2 == 0) {
			it_deq = deq.erase(it_deq);
			continue;
		}
		++it_deq;
	}

	getchar();

	return 0;
}

对于std::list,std::map,std::set等非顺序容器,正确的循环删除操作可以是下面的样子:

int main(int argc, char **argv)
{
	std::list<int> lst{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	auto it_lst = lst.begin();
	while (it_lst != lst.end()) {
		if (*it_lst % 2 == 0) {
			it_lst = lst.erase(it_lst);
			continue;
		}
		++it_lst;
	}

	std::map<int, char> mp{ { 0, '0' }, { 1, '1' }, { 2, '2' }, { 3, '3' }, { 4, '4' }, { 5, '5' }, { 6, '6' }, { 7, '7' }, { 8, '8' }, { 9, '9' } };
	auto it_mp = mp.begin();
	while (it_mp != mp.end()) {
		if (it_mp->first % 2 == 0) {
			it_mp = mp.erase(it_mp);
			continue;
		}
		++it_mp;
	}

	std::set<int> st{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	auto it_st = st.begin();
	while (it_st != st.end()) {
		if (*it_st % 2 == 0) {
			it_st = st.erase(it_st);
			continue;
		}
		++it_st;
	}

	getchar();

	return 0;
}

也可以是下面的样子:

int main(int argc, char **argv)
{
	std::list<int> lst{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	auto it_lst = lst.begin();
	while (it_lst != lst.end()) {
		if (*it_lst % 2 == 0) {
			lst.erase(it_lst++);
			continue;
		}
		++it_lst;
	}

	std::map<int, char> mp{ { 0, '0' }, { 1, '1' }, { 2, '2' }, { 3, '3' }, { 4, '4' }, { 5, '5' }, { 6, '6' }, { 7, '7' }, { 8, '8' }, { 9, '9' } };
	auto it_mp = mp.begin();
	while (it_mp != mp.end()) {
		if (it_mp->first % 2 == 0) {
			mp.erase(it_mp++);
			continue;
		}
		++it_mp;
	}

	std::set<int> st{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	auto it_st = st.begin();
	while (it_st != st.end()) {
		if (*it_st % 2 == 0) {
			st.erase(it_st++);
			continue;
		}
		++it_st;
	}

	getchar();

	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章