程序中有一段代碼是關於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;
}