我有以下代码:
//update it in the map
std::map<std::string, std::string>::iterator it;
for(it = spreadsheets.at(i).cells.begin(); it != spreadsheets.at(i).cells.end(); ++it)
{
if(it->first == change.first)
{
if(change.second == "")
{
spreadsheets.at(i).cells.erase(change.first);
}
else
{
it->second = change.second;
}
}
}
上面的代码完全在我的Mac上运行然而当我在Linux计算机上运行时,它会在spreadsheets.at(i).cells.erase(change.first);
有什么想法导致这个错误吗?我曾尝试将erase(change.first)
更改为erase(it)
,我仍然遇到了段错误。
答案 0 :(得分:4)
因为当您从容器中删除时,您的迭代器不再有效,但您的循环仍在继续。
您可以将循环更改为:
std::map<std::string, std::string>::iterator it = spreadsheets.at(i).cells.begin();
while (it != spreadsheets.at(i).cells.end())
{
if(it->first == change.first)
{
if(change.second == "")
{
spreadsheets.at(i).cells.erase(it++); //Post increment returns a copy pointing at the current element, while it already points to the next element and thus stays valid after erase
}
else
{
it->second = change.second;
++it;
}
}
else
++it;
}
现在我想到了,为什么要用迭代器指向的第一个元素擦除,即:
spreadsheets.at(i).cells.erase(change.first);
而不是
spreadsheets.at(i).cells.erase(it);
效率较低,因为必须进行另一次查找。
答案 1 :(得分:4)
来自std::map::erase
的文档:
擦除元素的引用和迭代器无效。其他引用和迭代器不受影响。
你的循环仍然继续,你增加你的(现在无效的)迭代器。
修复:以另一种方式递增迭代器,例如:
std::map<std::string, std::string>::iterator it;
for (it = spreadsheets.at(i).cells.begin(); it != spreadsheets.at(i).cells.end();/*NOTE: no increment here*/)
{
if (it->first == change.first)
{
if (change.second == "")
{
it = spreadsheets.at(i).cells.erase(it); // C++11 only
// in both C++03 and C++11: spreadsheets.at(i).cells.erase(it++);
}
else
{
it->second = change.second;
++it;
}
}
else
++it;
}
或者为了避免混淆,因为有许多执行路径(让我忘记第一次尝试时的最后一个else
的混淆):只需复制迭代器,递增原始路径,然后使用副本。在您的情况下,这可能看起来有点过分,但对于更复杂的循环,这有时是保持理智的唯一方法。 ;)
std::map<std::string, std::string>::iterator it;
for (it = spreadsheets.at(i).cells.begin(); it != spreadsheets.at(i).cells.end();/*NOTE: no increment here*/)
{
std::map<std::string, std::string>::iterator this_it = it++;
if (this_it->first == change.first)
{
if (change.second == "")
{
spreadsheets.at(i).cells.erase(this_it);
}
else
{
this_it->second = change.second;
}
}
}
答案 2 :(得分:2)
从地图中删除元素后,指向此元素将变为无效。因此spreadsheets.at(i).cells.erase(change.first);
呈现it
无效。见Iterator Invalidation Rules
答案 3 :(得分:0)
当你执行spreadsheets.at(i).cells.erase(change.first);
时,std :: map中的迭代器(在当前的change.first键处)无效。因此,当您执行it++
时,它是未定义的行为。
cf Rules for Iterator Invalidation了解有关标准容器中迭代器失效的规则
答案 4 :(得分:0)
在删除迭代器之前递增它。为什么不在Mac上发生?谁知道......不同的操作系统,不同的行为。
答案 5 :(得分:0)
擦除元素的引用和迭代器无效。
//update it in the map
std::map<std::string, std::string>::iterator it;
for(it = spreadsheets.at(i).cells.begin(); it != spreadsheets.at(i).cells.end(); ++it)
{
if(it->first == change.first)
{
if(change.second == "")
{
spreadsheets.at(i).cells.erase(it--);
}
else
{
it->second = change.second;
}
}
}