通过for循环从C++映射中删除元素

Pet*_*ter 15 c++ stl map c++11

我的STL有点生疏,请原谅我提出一个可能微不足道的问题.考虑以下代码:

map<int,int> m;
...
for (auto itr = m.begin(); itr != m.end(); ++itr) {
    if (itr->second == 0) {
        m.erase(itr);
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是:在循环地图时擦除元素是否安全?

Eri*_*rik 23

是的,但不是你这样做的方式.擦除时会使itr无效,然后递增无效迭代器.

auto itr = m.begin();
while (itr != m.end()) {
  if (itr->first == 0) {
    m.erase(itr++);
  } else {
    ++itr;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • @ Ben,@ Erik:一个警告,标准中有两种`erase`方法,基于节点的容器(`list`,`map`,`set`,...)使用这个方法,用于容器其`erase`方法返回一个迭代器(如`vector`),`erase`行应该是`itr = m.erase(itr)`.这个签名怪癖有效地阻止了整个"可互换性"的事情......所以在C++ 0x中得到纠正,这样所有没有返回任何东西的`erase`现在都会返回到下一个元素的迭代器:) (9认同)
  • @dlanod失去了`++`:`itr = m.erase(itr);`它应该是什么,参见例如http://en.cppreference.com/w/cpp/container/map/erase (5认同)
  • auto tmp = ++ itr; m.erase(ITER); itr = tmp; //这将更加明显(IMO). (2认同)
  • 它也是错的,你在擦除之前递增......你是否打算例如`auto tmp = itr; ++ ITR; m.erase(tmp);`? (2认同)

XAd*_*der 11

我认为你根本不应该使用删除的迭代器 - 如果列表导致严重的问题,那么对于地图来说应该不同.

由Matthieu M 编辑:此代码在C++ 0x中格式良好,并允许作为MSVC的扩展.

map<int,int> m;
...
auto itr = m.begin();
while (itr != m.end())
{
    if (itr->second == 0) {
        itr = m.erase(itr);
    }
    else 
    {
        itr++;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 标准c ++ map :: erase确实*不*返回一个新的迭代器,这是一个MSVC扩展. (2认同)
  • @Xader:我已经恢复了你的编辑并添加了一个免责声明,这段代码在C++ 0x中构造良好,并且是**删除容器中元素的规范方法,因此给出了最好的答案.(免责声明是那些不理解"auto"意味着C++ 0x的人不会感到困惑).nay-sayers的标准参考:n3225 23.5.1.2元素访问. (2认同)

dec*_*ype 8

对于给出的示例,实际上更容易使用将键作为参数的擦除重载.此函数使用给定键擦除地图中的所有元素(对于地图,此值始终为零或一个元素)

map<int,int> m; 
// ...
m.erase(0); // erase all elements with key equivalent to 0
Run Code Online (Sandbox Code Playgroud)