zoukankan      html  css  js  c++  java
  • STL容器的遍历删除

    STL容器的遍历删除
           今天在对截包程序的HashTable中加入计时机制时,碰到这个问题。对hash_map中的每个项加入时间后,用查询函数遍历hash_map,以删除掉那些在表存留时间比某个阈值长的表项(当然这个函数是应该运行在另起一个线程上的),但是在按照下面的方法对hash_map(用迭代器)遍历删除时,当找到第一个满足删除条件的元素并将其删除后,程序将提示非法:
    for(list<int>::iterator iter = m_map.begin(); iter != m_map.end(); ++iter)  //这种做法是错误的
    {
        if(需要删除)
        {
            m_map.erase(iter);
        }
    }
    
    原因是当前节点已经被删除后,其使用的内存空间被释放的,那么再对已经删除的节点获得位置信息,这种访问当然就是非法的。
    正确的做法是:
    for(list<int>::iterator iter = m_map.begin(); iter != m_map.end(); )  //这是正确的做法
    {
        if(需要删除)
        {
            m_map.erase(iter++);
        }
        else
            ++iter;
    }
    
    为什么呢?
    
        map 是关联容器,由节点组成,每个节点都有自己独立的存储空间。除了包含元素对象之外,节点中还包含定位其前后相邻节点的位置信息(一般用指针表示),而且在 定位前、后节点(即对迭代器进行自减、自加运算)时都要根据当前节点中的位置信息进行计算。显然,如果此时当前节点已经被删除、其使用的内存空间被释放的 话,那么为了获得位置信息再对已经删除的节点进行访问就是非法的。
    
        STL中对结点类容器(如list,hash_map)遍历时进行删除时,涉及到iterator的相关操作(以list为例):
    _Self& operator++()
    {
        this->_M_incr();
        return *this;  
    }
    _Self operator++(int)
    {    _Self __tmp = *this;
        this->_M_incr();
        return __tmp;               //后缀++按照语意返回了++前的iterator,
    }
    void _M_incr() { _M_node = _M_node->_M_next; }    //++的操作是使iterator的_M_node指向下一个结点
    
    iterator erase(iterator __position)
    {   _List_node_base* __next_node = __position._M_node->_M_next;
        _List_node_base* __prev_node = __position._M_node->_M_prev;
        _Node* __n = (_Node*) __position._M_node;
        __prev_node->_M_next = __next_node;
        __next_node->_M_prev = __prev_node;  
        _STLP_STD::_Destroy(&__n->_M_data); //call T::~T()
        this->_M_node.deallocate(__n, 1);            
        return iterator((_Node*)__next_node);
    
    } 
        分析代码我们可以看出,erase会释放掉__position的_M_node, 在__position上再进行++是错误的。
    所以不能在m_map.erase(iter)后,进行iter++。
    
    
    哪为什么m_map.erase(iter++)可以呢?为什么不能用m_map.erase(++iter)?
        参照operator ++的代码我们可以找到答案。iter++返回了++之前的iter值,erase使用这个值能正确进行__position的前后结点的串接及删除正确 的结点,而++iter返回的是++之后的iter,所以m_map.erase(++iter)后串接不正确,iter->_M_node也是失 效的。
        另外,对于非结点类,如数组类的容器vector,string,deque,如果erase会返回下个有效的iterator,可以这样处理:
    
    for(vector<int>::iterator iter = m_vector.begin(); iter != m_vector.end();)
    {
        if(需要删除)
        {
            iter=m_vector.erase(iter);
        }
        else
            ++iter;
    }
  • 相关阅读:
    删除数据库时报错 ERROR 1010 (HY000): Error dropping database (can't rmdir './cart', errno: 39)
    多线程异步操作导致异步线程获取不到主线程的request信息
    使用mybatis更新数据时 时间字段的值自动更新
    mysql死锁com.mysql.cj.jdbc.exception.MYSQLTransactionRollbackException Deadlock found when trying to get lock;try restarting transaction
    mysql 执行报错:Error querying database. Cause: java.sql.SQLSyntaxErrorException:which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
    Linux系统下部署eleasticsearch+kibana
    navicat突然连接不上远程linux服务器上的mysql
    即使是一条咸鱼,也要做最咸的那条
    linux环境下安装jdk,tomcat
    SpringBoot如何内置Tomcat
  • 原文地址:https://www.cnblogs.com/timssd/p/4160659.html
Copyright © 2011-2022 走看看