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;
}

 

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