剖析STL容器遍历删除时诡异的erase(iter++)

    技术2022-05-11  90

    我们知道STL中结点类容器(如:list,hash_map)遍历时进行删除时,需要这样做:

    for(list<int>::iterator iter = m_list.begin(); iter != m_list.end(); ){    if(需要删除)    {        m_list.erase(iter++);    }    else        ++iter;}而不能这样:for(list<int>::iterator iter = m_list.begin(); iter != m_list.end(); ++iter){    if(需要删除)    {        m_list.erase(iter);    }}为什么呢?

    以STL list为例:iterator的相关操作_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; }    //++的操作对于list结构来说,就是使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;  //上面的代码把删除结点__position的前后结点串起来,而移除_positoin    _STLP_STD::_Destroy(&__n->_M_data); //call T::~T()    this->_M_node.deallocate(__n, 1);            //释放结点内存    return iterator((_Node*)__next_node);} 分析代码我们可以看出,erase会deallocate__position的_M_node, 在__position上再进行++是错误的。所以不能在m_list.erase(iter)后,进行iter++.哪为什么m_list.erase(iter++)可以呢?为什么不能用m_list.erase(++iter)?参照operator++的代码我们可以找到答案,iter++返回了++之前的iter值,erase使用这个值能正确进行__position的前后结点的串接及删除正确的结点,而++iter返回的是++之后的iter,所以m_list.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;}


    最新回复(0)