如何用迭代器删除std :: map的元素?

时间:2011-01-05 03:25:28

标签: c++ map iterator stdmap

我想循环浏览std::map并根据内容删除项目。如何做到最好?

3 个答案:

答案 0 :(得分:96)

如果你有一个符合C ++ 11标准的编译器,这里有一个简单的方法:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       itr = myMap.erase(itr);
    } else {
       ++itr;
    }
}

我们的想法是将迭代器从容器的开头向前移动到最后,检查每一步是否应删除当前的键/值对。如果是这样,我们使用erase成员函数删除迭代的元素,该函数然后将迭代器返回到映射中的下一个元素。否则,我们会正常推进迭代器。

如果您没有符合C ++ 11标准的编译器,或者您正在使用较旧的代码库,那么事情就会有点棘手。在C ++ 11之前,erase成员函数不会将迭代器返回到映射中的下一个元素。这意味着为了在迭代时删除元素,您需要使用三部分舞蹈:

  1. 复制当前迭代器。
  2. 将当前迭代器推进到下一个元素。
  3. 在旧迭代器的副本上调用erase
  4. 此处显示:

    std::map<K, V>::iterator itr = myMap.begin();
    while (itr != myMap.end()) {
        if (ShouldDelete(*itr)) {
           std::map<K, V>::iterator toErase = itr;
           ++itr;
           myMap.erase(toErase);
        } else {
           ++itr;
        }
    }
    

    这个过程是必需的,因为如果你只是在迭代器上调用erase,那么使无效,这意味着增量和减量等操作会导致未定义的行为。上面的代码通过设置迭代器的副本,推进itr以便它在下一个元素,然后擦除迭代器的临时副本来解决这个问题。

    使用一些Clever Trickiness,可以以牺牲可读性为代价缩小此代码。以下模式在较旧的C ++代码中很常见,但在C ++ 11中不是必需的:

    std::map<K, V>::iterator itr = myMap.begin();
    while (itr != myMap.end()) {
        if (ShouldDelete(*itr)) {
           myMap.erase(itr++);  // <--- Note the post-increment!
        } else {
           ++itr;
        }
    }
    

    这里使用后增量运算符是一种巧妙的方法来制作旧迭代器的副本(记住postfix ++运算符返回原始迭代器值的副本),同时也推进旧的迭代器。

答案 1 :(得分:8)

for(MyMap::iterator it = mymap.begin(); it!=mymap.end(); ) {
  if(mycondition(it))
    it = mymap.erase(it);
  else
    it++;
}

编辑:似乎这只适用于MSVC

edit2:在c ++ 0x中,这也适用于关联容器

答案 2 :(得分:7)


这是一个简单的方法:

    int value_to_delete( 2 );
    for( std::map<int, int>::iterator i = mm.begin(); i != mm.end(); ) {
        if( i->second != value_to_delete ) {
            mm.erase( i++ ); // advance before iterator become invalid
        }
        else {
            ++i;
        }
    }