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

57 c++ iterator stdmap map

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

tem*_*def 101

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

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

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

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

  1. 复制当前迭代器.
  2. 将当前迭代器前进到下一个元素.
  3. 调用erase旧迭代器的副本.

这显示在这里:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这个过程是必需的,因为如果你刚刚调用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 对于矢量情况,逻辑是不同的(参见下面的Timo示例); 在擦除()之后,擦除点处或之后的所有迭代器都会失效.要知道在哪里拾取,您可以捕获erase()函数的值.使用映射,来自擦除的唯一无效迭代器是已删除元素的迭代器. (3认同)

Tim*_*imo 8

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

编辑:似乎这只适用于MSVC

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

  • 这适用于像std :: vector这样的序列容器,但不适用于像std :: map这样的关联容器.不同之处在于,在序列容器中,erase()将迭代器返回到下一个元素,而在关联容器中,它返回void. (5认同)

Cha*_*han 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;
        }
    }
Run Code Online (Sandbox Code Playgroud)