STL使用迭代器遍历和删除元素

STL使用迭代器遍历和删除元素

vector 迭代器使用不当造成挂死或死循环

错误用法

#include <vector>

void vec_erase_item(std::vector<int>& vec, int value){
    for(auto iter = vec.begin(); iter != vec.end(); iter++){
        printf("iter: %p, end(): %p\n", iter, vec.end());
        if(*iter == value){
            vec.erase(iter);
            printf("after erase, iter: %p, end(): %p\n", iter, vec.end());
        }
    }
}

int main(int argc, char** argv)
{
    std::vector<int> vec{0, 2, 4, 6, 8, 10, 1 ,3, 5, 7, 9};
    vec_erase_item(vec, 9);
    return 0;
}

运行结果:
run_error_use_result

当要删除的元素刚好是最后一个时,删除后相当于

iter = vec.end();
vec.end() = vec.end() - 1;

所以iter != vec.end()的条件是永远成立的,如果循环中没有对iter进行解引用(*iter),那么会造成死循环,否则,当访问了非法地址,会导致程序挂死。

正确用法

void vec_erase_item(std::vector<int>& vec, int value){
    for(auto iter = vec.begin(); iter != vec.end(); ){  // 此处不加iter++
        printf("iter: %p, end(): %p\n", iter, vec.end());
        if(*iter == value){
            iter = vec.erase(iter);
            printf("after erase, iter: %p, end(): %p\n", iter, vec.end());
        } else{
            iter++;
        }
    }
}

运行结果:
run_correct_use_result

vector erase 返回的迭代器指向下一元素,当删除的是尾元素时,返回的迭代器指向end()。

map 迭代器使用不当造成挂死

错误用法

#include <map>

void map_erase_item(std::map<int, int>& table, int value){
    for(auto iter = table.begin(); iter != table.end(); iter++){
        if(iter->second == value){
            table.erase(iter);
        }
    }
}
int main(int argc, char** argv)
{
    std::map<int, int> table = {
        {1, 100},
        {2, 200},
        {3, 300},
    };
    map_erase_item(table, 300);
    return 0;
}

程序执行后出现挂死,原因是map erase后迭代器已经失效,此后对迭代器的操作是未定义行为。

正确用法

void map_erase_item(std::map<int, int>& table, int value){
    for(auto iter = table.begin(); iter != table.end(); ){ // 此处不加iter++
        if(iter->second == value){
            table.erase(iter++);
            // iter = table.erase(iter); // 也可以用这种写法
        } else{
            iter++;
        }
    }
}

table.erase(iter++),相当于

auto tmp = iter + 1;
table.erase(iter);
iter = tmp;

table.erase(iter++) 也可以换为 iter = table.erase(iter); 的写法,erase返回的迭代器指向下一个元素。

posted @ 2022-12-11 21:24  流翎  阅读(560)  评论(0编辑  收藏  举报