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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值