如何使用for循环使用反向迭代器调用erase

log*_*lic 6 c++ c++11

关于这里提供的答案:如何使用反向迭代器调用erase

++it当使用-std = c ++ 11在g ++ 4.8.4中编译时,以下结果导致分段错误(on ).我误解了答案吗?

  std::map<int,int> testmap;
  testmap[0] = 1;
  for(auto it=testmap.rbegin(); it!=testmap.rend(); ++it) {
    testmap.erase( std::next(it).base() );
  }
Run Code Online (Sandbox Code Playgroud)

Jar*_*d42 10

erase 使迭代器无效,你必须从擦除返回重建它:

it = std::map<int,int>::reverse_iterator(testmap.erase( std::next(it).base() ));
Run Code Online (Sandbox Code Playgroud)

或(c ++ 11)

it = decltype(it){testmap.erase( std::next(it).base() )};
Run Code Online (Sandbox Code Playgroud)

演示.

为了完整性,这里是原始问题的校正循环的样子(注意迭代从以下位置删除for(...):

for (auto rit = testmap.rbegin(); rit != testmap.rend(); /* empty */) {
    if (WE_WANT_TO_ERASE(it)) {
        rit = decltype(rit){ testmap.erase(std::next(rit).base()) };
    } else {
        ++rit;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你"擦掉",别忘了跳过`++ it`,以免跳过一个元素. (4认同)

log*_*lic 2

在使用了这个习惯用法之后,我认为对 Jarod42 的答案中的循环进行修改是为了使事情更安全并保持典型的for(;;)循环细节:

for (auto it = testcont.rbegin(), nit = it; it != testcont.rend(); it = nit) {
    nit = next(it);

    // whatever... maybe a continue somewhere or maybe not

    if (WE_WANT_TO_ERASE(it)) {
        nit = decltype(it){ testcont.erase(std::next(it).base()) };
    }

    // whatever... maybe a continue somewhere or maybe not
}
Run Code Online (Sandbox Code Playgroud)

在另一个答案中使用循环太危险了。如果不加思索地continue;在循环中的某个位置添加 a ,而不首先递增迭代器,结果将是无限循环。因为乍一看,这看起来像一个正常的for(;;)循环,所以我相信这迟早会发生。类似地,如果循环中有分支,并且其中一个分支忽略递增迭代器,则会引入另一个错误。最后,如果您执行 an 操作erase(),则需要确保递增continue迭代器之前执行此操作,否则您会遇到另一个错误。

使用上面修改后的循环,可以像正常循环一样对待循环for(;;)。技巧是将增量nit(“下一个迭代器”)作为循环体的第一行。那你就不用担心了。您唯一需要更新的时间nit是如果您正在执行erase(). 其他一切都按照人们期望的 for 循环的方式工作。

最后一点:我最初问的是有关地图的问题,但这也适用于vectorlist等。