在迭代时从地图(或任何其他STL容器)中删除/删除内容

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在迭代时从地图(或任何其他STL容器)中删除/删除内容相关的知识,希望对你有一定的参考价值。

据称,当迭代器变为无效时,您不能在迭代时擦除/删除容器中的元素。删除满足特定条件的元素的(安全)方法是什么?请只是stl,没有提升或tr1。

编辑如果我想删除符合某个标准的元素,可能使用仿函数和for_each或擦除算法,是否有更优雅的方法?

答案
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}
另一答案

只要在删除迭代器后它就不会使迭代器无效:

MyContainer::iterator it = myContainer.begin();
while(it != myContainer.end())
{
    if (*it == matchingValue)
    {
       myContainer.erase(it++);
    }
    else
    {
        ++it;
    }
}
另一答案

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

}
另一答案

Viktor的解决方案具有在移除之前能够对元素执行某些操作的好处。 (我无法用remove_ifremove_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<int>(), 4 )或类似的东西:

struct Predicate : public unary_function<int, bool>
{
    int mExpected;
    Predicate(int desired) : mExpected(desired) {}
    bool operator() (int input)
    {
        return ( input == mExpected );
    }
};
另一答案

我更喜欢与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;    
  }
}

使用while,没有任何危险可以在it循环中增加for两次。

另一答案

1.对于std::vector<>

std::vector <int> vec;
vec.erase(std::remove(vec.begin(),vec.end(), elem_to_remove), vec.end());

2.对于std::map<>总是使用std::map::erase()

std::map<int,std::string> myMap;
myMap.emplace(std::make_pair(1, "Hello"));
myMap.emplace(std::make_pair(2, "Hi"));
myMap.emplace(std::make_pair(3, "How"));
myMap.erase( 1);//Erase with key
myMap.erase(myMap.begin(), ++myMap.begin() );//Erase with range
for( auto &ele: myMap)
{
    if(ele.first ==1)
    {
        myMap.erase(ele.first);//erase by key 
        break; //You can't use ele again properly 
               //wthin this iteration, so break.
    }
}
  1. 对于std::list使用std::list::erase()
另一答案

markh44是最STL-ish的反应。但请注意,通常,通过修改容器使迭代器无效,但set和map是异常。在那里,您可以删除项目并继续使用迭代器,除非您删除迭代器引用的项目。

另一答案

使用post-decrement运算符在递减之前返回迭代器的副本这一事实。由于在擦除当前元素后递减的迭代器仍然有效,因此for循环继续按预期运行。

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

编辑:如果您尝试删除列表中的第一个元素,则不起作用....

另一答案
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;
    }
}

以上是关于在迭代时从地图(或任何其他STL容器)中删除/删除内容的主要内容,如果未能解决你的问题,请参考以下文章

仅通过迭代器删除 STL 容器元素

怎么删除STL容器的元素

6.5-数据结构&算法-标准模板STL/STL容器/向量

C++ STL容器在for循环中删除迭代器 正确方法 it++正确吗

C++ STL容器在for循环中删除迭代器 正确方法 it++正确吗

STL容器之<set>