Erase/Remove contents from the map (or any other STL container) while iterating it

前端 未结 9 1325
无人及你
无人及你 2020-12-01 07:55

Allegedly you cannot just erase/remove an element in a container while iterating as iterator becomes invalid. What are the (safe) ways to remove the elements that meet a cer

相关标签:
9条回答
  • 2020-12-01 08:18
    bool IsOdd( int i )
    {
        return (i&1)!=0;
    }
    
    int a[] = {1,2,3,4,5};
    vector<int> v( a, a + 5 );
    v.erase( remove_if( v.begin(), v.end(), bind1st( equal_to<int>(), 4 ) ), v.end() );
    // v contains {1,2,3,5}
    v.erase( remove_if( v.begin(), v.end(), IsOdd ), v.end() );
    // v contains {2}
    
    0 讨论(0)
  • 2020-12-01 08:18

    Use the fact that the post-decrement operator returns a copy of the iterator before it decrements. Since the decremented iterator is still valid after erasing the current element, the for loop continues to operate as intended.

    #include <list>
    std::list<int> myList;
    for(int i = 0; i < 10; ++i )
    {
       myList.push_back(i);
    }
    
    int cnt = 0;
    for(std::list<int>::iterator iter = myList.begin(); iter != myList.end(); ++iter)
    {
       if( cnt == 5 )
       {
          myList.erase(iter--);
       }
       ++cnt;
    }
    

    Edit: Doesn't work if you attempt to erase the first element in the list....

    0 讨论(0)
  • 2020-12-01 08:20

    Example with std::vector

    #include <vector>
    
    using namespace std;
    
    int main()
    {
    
       typedef vector <int> int_vector;
    
       int_vector v(10);
    
       // Fill as: 0,1,2,0,1,2 etc
       for (size_t i = 0; i < v.size(); ++i){
          v[i] = i % 3;
       }
    
       // Remove every element where value == 1    
       for (int_vector::iterator it = v.begin(); it != v.end(); /* BLANK */){
          if (*it == 1){
             it = v.erase(it);
          } else {
             ++it;
          }
       }
    
    }
    
    0 讨论(0)
  • 2020-12-01 08:24

    I prefer version with while:

    typedef std::list<some_class_t> list_t;
    void f( void ) {
      // Remove items from list
      list_t::iterator it = sample_list.begin();
      while ( it != sample_list.end() ) {
        if ( it->condition == true ) {
          it = sample_list.erase( it );
        } else ++it;    
      }
    }
    

    With while there is no danger to increment it twice as it could be in for loop.

    0 讨论(0)
  • 2020-12-01 08:24
    template <class Container, class Predicate>
    void eraseIf( Container& container, Predicate predicate  ) {
        container.erase( remove_if( container.begin(), container.end(), predicate ), container.end() );
    }   
    
    // pre-c++11 version
    template<class K, class V, class Predicate> 
    void eraseIf( std::map<K,V>& container, Predicate predicate) {
        typename std::map<K,V>::iterator iter = container.begin();
        while(iter!=container.end()) { 
            iterator current = iter++;
            if(predicate(*current))
                container.erase(current);
        }
    }
    
    // c++11 version
    template<class K, class V, class Predicate> 
    void eraseIf( std::map<K,V>& container, Predicate predicate) {
        auto iter = container.begin();
        while(iter!=container.end()) {
            if(predicate(*iter))
                iter = container.erase(iter);
            else
                ++iter;
        }
    }
    
    0 讨论(0)
  • 2020-12-01 08:29

    You can as long as you don't invalidate your iterator after you've erased it:

    MyContainer::iterator it = myContainer.begin();
    while(it != myContainer.end())
    {
        if (*it == matchingValue)
        {
           myContainer.erase(it++);
        }
        else
        {
            ++it;
        }
    }
    
    0 讨论(0)
提交回复
热议问题