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



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

当在g++4.8.4中用-std=c++11编译时,以下结果会导致分段错误(在++it上)。我是不是误解了答案?

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

erase使迭代器无效,因此您必须根据erase:的返回值重新构建它

it = std::map<int,int>::reverse_iterator(testmap.erase( std::next(it).base() ));

或者使用C++11:

it = decltype(it){testmap.erase( std::next(it).base() )};

或者使用C++17:

it = std::reverse_iterator(testmap.erase( std::next(it).base() ));

演示。

为了完整起见,以下是原始问题中更正的循环的样子(注意,迭代器增量已从for(...)中删除):

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

在使用了这个习语之后,我认为对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
}

在另一个答案中使用循环太危险了。如果在循环中的某个地方轻率地添加continue;,而不首先递增迭代器,那么结果将是一个无限循环。因为,在最初的glace中,这看起来像一个正常的for(;;)循环,我相信这迟早会发生。类似地,如果循环中有分支,并且其中一个分支忽略了迭代器的增量,则会引入另一个错误。最后,如果您执行erase(),那么在递增迭代器之前,您需要确定continue,否则您将有另一个错误。

使用上面修改的循环,可以像对待普通for(;;)循环一样对待该循环。诀窍是将nit("下一个迭代器")作为循环体的第一行递增。那你就不用担心了。唯一需要更新nit的时间是如果您正在执行erase()。其他一切都像人们期望的for循环一样工作。

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

相关内容

  • 没有找到相关文章

最新更新