2015-09-26 47 views
0

我有一个像这样的地图for循环。这个地图擦除是否安全?

std::map<int,std::string> mymap = {{1,"a"},{2,"b"},{3,"c"}}; 

for(std::map<int,std::string>::iterator it = mymap.begin(); it!=mymap.end(); ++it) 
{ 
    if(it->first==3) 
    { 
     mymap.erase(it); 
    } 
} 

std::cout << mymap.rbegin()->second << std::endl; 

如预期的那样输出为“b”。问题是:这会导致无限循环(或崩溃)吗?我的意思是

erase(it) 

这个迭代器它是无效的。如果擦除的项目不是最后一个,它应该是可以的,因为在擦除之后“它”递增,并且当评估条件时它指向最大值为mymap.end()。但是,如果我擦除最后一个,擦除后mymap.end()应该在最后剩下的项目之后,然后它会增加。难道它不能以某种方式超出范围?我不应该使用类似

for(std::map<int,std::string>::iterator it = mymap.begin(); it!=mymap.end(); ++it) 
{ 
    std::map<int,std::string>::const_iterator tempit = it; 
    const bool lastItemErased = ++tempit == mymap.end(); 

    if(it->first==3) 
    { 
     mymap.erase(it); 
    } 

    if(lastItemErased) break; 
} 

要安全吗?

注意:如果我试图用键3和2擦除元素,上述两种运行和行为都与预期相同。我不明白这是如何实现的,为什么它不会崩溃。我如何增加一个无效的迭代器?

更新:它必须使用c + + 03。我像这样初始化了地图,以便更容易地发布问题。

+0

如果迭代器失效,那么根据定义,使用它是不安全的。这是“未定义”的行为,所以任何事情都可能发生。 – Galik

+0

为了安全使用,请参考以下文档中的示例:http://en.cppreference.com/w/cpp/container/map/erase – Galik

+0

擦除后使用rbegin将从地图获取最后一个元素,那么为什么你认为它应该崩溃?如果您使用的是前向迭代器,则必须按照链接中的答案指出的方式进行操作,以将问题标记为重复的问题。 – Invictus

回答

1

编辑:只适用于C++ 11及以上。

std::map::erase返回一个新的有效迭代器对象(即在您的示例中为mymap.end()后面的元素)。您应该使用该返回值:

for(std::map<int,std::string>::iterator it = mymap.begin(); it!=mymap.end();) 
{ 
    if(it->first==3) 
    { 
     it = mymap.erase(it); 
    } 
    else 
    { 
     ++it; 
    } 
} 

请参阅http://en.cppreference.com/w/cpp/container/map/erase以供参考。

+0

对不起。它必须与C++ 03一起工作。我像这样初始化了地图,以便更容易地发布问题。 – TmsKtel

+1

@LukasW你的解决方案跳过一些迭代 –

+0

你说得对,@Galik&Piotr,我会纠正它。无论如何,新的C++ 03要求使这个答案无用。 –