• C++有关unordered_map::erase的奇怪bug


    背景

    项目中使用unordered_map保存方便使用key快速索引对象
    需要每次使用后根据key判断是否删除过期pair代码如下:

    for(auto& pair : m)
    {   
        if(!condition(pair.first))
        {
            m.erase(pair.first);
        }
    }
    

    捉虫

    开始代码跑起来没问题,不久出现端倪偶发报错
    打断点显示在if传入condition的pair为空抛出异常
    仔细反思应该是erase发生清除后map长度变短
    而for继续按照初始长度进行遍历直至越界

    修复

    既已定位到问题,尝试改写for逻辑

    for (auto it = m.begin(); it != m.end(); )
    {
        if(!condition(it->first)) 
        {
            m.erase(it++); 
        }
        else
        {
            ++it;
        }
    }
    

    优雅

    自C++11后map::erase(itor)方法默认返回下一个itor可以用while改写

    auto it = m.begin();
    while(it != m.end())
    {
        if(!condition(it->first))
        {
            pair = m.erase(it);
        }
        else
        {
            ++it;
        }
    }
    

    深入

    仔细思考还有些许疑惑未解
    每次earse发生可能触发unordered_map内部rehashing
    上述方法仅保证遍历不越界
    无法避免某个itor被略过或反复操作的可能
    查阅cpp reference对此作出的解释为

    C++14 Iterator validity
    Only the iterators and references to the elements removed are invalidated.
    The rest are unaffected.
    The relative order of iteration of the elements not removed by the operation is preserved.

    C++11没有第三句话,故使用-std=c++14编译确保上述逻辑正确
    下次遇到还是老老实实开个vector保存待清除key逐个调用erase最为稳妥吧……

    参考

    c++ - Problem with std::map::iterator after calling erase() - Stack Overflow
    unordered_map::erase - C++ Reference

  • 相关阅读:
    数据挖掘相关资料收集(持续更新)
    常见面试之机器学习算法思想简单梳理
    在c中保存状态
    lua 和 c
    lua 基础库
    lua 面向对象
    lua 高级
    lua 基础
    lua中的协程
    cocos2d中的可见性检测
  • 原文地址:https://www.cnblogs.com/azureology/p/15637503.html
Copyright © 2020-2023  润新知