我有这样的地图:
map<prmNode,vector<prmEdge>,prmNodeComparator> nodo2archi;
当我必须更新值(向量)时,我取出键和他的值,我更新值的向量,我擦除旧键和值然后我插入键和新向量。代码是这样的:
bool prmPlanner::insert_edgemap(int from,int to) {
prmEdge e;
e.setFrom(from);
e.setTo(to);
map<prmNode,vector<prmEdge> >::iterator it;
for (it=nodo2archi.begin(); it!=nodo2archi.end(); it++){
vector<prmEdge> appo;
prmNode n;
n=(*it).first;
int indice=n.getIndex();
if (indice==f || indice==t){
appo.clear();
vector<prmEdge> incArchi;
incArchi=(*it).second;
appo=(incArchi);
appo.push_back(e);
nodo2archi.erase(it);
nodo2archi.insert(make_pair(n,appo) );
}
}
return true;
}
问题在于,对于前40-50次迭代,所有内容都会变得更好,并且地图会更新,而有了更多的迭代,有时会出现分段错误,有时会出现无限空闲。我不知道为什么。有人可以帮我吗? 非常感谢你。
答案 0 :(得分:4)
您正在迭代nodo2archi
,同时通过nodo2archi.erase(it);
和nodo2archi.insert(make_pair(n,appo) );
更改其大小。如果你这样做,你的迭代器可能会变得无效,你的it++
可能会崩溃。
答案 1 :(得分:2)
问题是在擦除迭代器it
之后,你试图对它执行操作(增量),这是未定义的行为。一些答案声明在迭代时修改容器是UB,这不是真的,但你必须知道迭代器何时失效。
对于序列容器,erase
操作会将新的有效迭代器返回到容器中的下一个元素,因此这将是从这样的容器中擦除的正确且惯用的方法:
for ( SequenceContainer::iterator it = c.begin(); it != c.end(); )
// note: no iterator increment here
// note: no caching of the end iterator
{
if ( condition(*it) ) {
it = c.erase(it);
} else {
++it;
}
}
但遗憾的是,在当前标准中,关联容器erase
不返回迭代器(这在新标准草案中已修复),因此您必须手动伪造它
for ( AssociativeContainer::iterator it = c.begin(); it != c.end(); )
// again, no increment in the loop and no caching of the end iterator
{
if ( condition(*it) ) {
AssociativeContainer::iterator del = it++; // increment while still valid
c.erase(del); // erase previous position
} else {
++it;
}
}
更令人遗憾的是,第二种方法,对于关联容器是正确的,对某些序列容器(特别是std :: vector)无效,因此没有单一的解决方案来解决问题,你必须知道你在迭代什么过度。至少在出版下一个标准并且编制者赶上之前。
答案 2 :(得分:2)
您是否只是尝试将数据附加到某些映射的向量中?在这种情况下,您不需要删除和插入任何内容:
for (MapType::iterator it = map.begin(); it != map.end(); ++it) {
if (some_condition) {
it->second.push_back(some_value);
}
}
答案 3 :(得分:1)
Yo 在迭代时修改集合。
答案 4 :(得分:0)
在迭代地图时,您正在擦除节点。这是在寻找麻烦:)
答案 5 :(得分:0)
迭代时,不得修改集合本身。 C ++会允许它,但它仍会导致未定义的行为。其他语言(如Java)具有快速失败的迭代器,它们在修改集合时会立即中断。