Сотрите/Удалите содержание из карты (или любой другой контейнер STL) при итерации его

Это выглядит глупо для меня. Но я был в той же ситуации, и я вернулся к отмененным коммитам. Я сделал возврат чисел, поэтому мне приходилось делать возврат для каждого «возврата фиксации».

Теперь моя история коммитов выглядит немного странно.

weird history

Это любимый проект, так что все в порядке. Но для реального проекта я бы предпочел перейти к последнему коммиту, прежде чем вернуться, чтобы восстановить весь возвращенный код вместе в одном коммите и более разумном комментарии.

26
задан Lightness Races with Monica 26 January 2012 в 12:15
поделиться

7 ответов

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}
9
ответ дан 28 November 2019 в 06:39
поделиться

Вы можете, если не аннулируете свой итератор после его стирания:

MyContainer::iterator it = myContainer.begin();
while(it != myContainer.end())
{
    if (*it == matchingValue)
    {
       myContainer.erase(it++);
    }
    else
    {
        ++it;
    }
}
33
ответ дан 28 November 2019 в 06:39
поделиться
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;
    }
}
1
ответ дан 28 November 2019 в 06:39
поделиться

Пример с 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;
      }
   }

}
10
ответ дан 28 November 2019 в 06:39
поделиться

Я предпочитаю версию с , а :

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

С , в то время как нет опасности увеличить это вдвое, как это могло бы быть в для петля.

2
ответ дан 28 November 2019 в 06:39
поделиться

markh44 - это самый STL-подобный ответ. Обратите внимание, однако, что в общем случае итераторы становятся недействительными при изменении контейнера, но set и map являются исключениями. Там вы можете удалить элементы и по-прежнему использовать итераторы, за исключением случаев, когда вы удаляете тот самый элемент, на который ссылается итератор.

1
ответ дан 28 November 2019 в 06:39
поделиться

Решение Виктора имеет тот плюс, что можно что-то сделать с элементом перед удалением. (Я не смог сделать этого с remove_if или remove_copy_if). Но я предпочитаю использовать std::find_if, чтобы никогда не увеличивать итератор самостоятельно:

typedef vector<int> int_vector;
int_vector v;

int_vector::iterator itr = v.begin();
for(;;)
{
    itr = std::find_if(itr, v.end(), Predicate(4));
    if (itr == v.end())
    {
        break;
    }

    // do stuff with *itr here

    itr = v.erase(itr);  // grab a new, valid iterator
}

Где предикат может быть bind1st( equal_to(), 4 ) или что-то вроде этого:

struct Predicate : public unary_function<int, bool>
{
    int mExpected;
    Predicate(int desired) : mExpected(desired) {}
    bool operator() (int input)
    {
        return ( input == mExpected );
    }
};
3
ответ дан 28 November 2019 в 06:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: