关于这里提供的答案:如何使用反向迭代器调用擦除
当在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循环一样工作。
最后一点:我最初问的是关于地图的问题,但这也适用于vector
、list
等。