“擦除”后映射迭代器行为
Map iterator behavior after 'erase'ing
我在下面写这段代码,发现了这个奇怪的行为:
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<int, string> map1;
map1[1] = "Hello";
map1[2] = "Hello1";
map1[3] = "Hello2";
map1[4] = "Hello3";
map1[5] = "Hello4";
map<int, string>::iterator it;
for (it = map1.begin(); it != map1.end(); /*it++*/)
{
cout << "Enter: " << (int)(it->first) << endl;
if (it->first == 3)
map1.erase(it);
it++;
cout << "Exit: " << (int)(it->first) << endl;
}
return 0;
}
输出是:
Enter: 1
Exit: 2
Enter: 2
Exit: 3
Enter: 3
Exit: 4
Enter: 4
Exit: 5
Enter: 5
Exit: 4
当我仅在 for 循环中增加迭代器 it
时(检查注释迭代器),输出如下:
Enter: 1
Exit: 1
Enter: 2
Exit: 2
Enter: 3
Exit: 3
Enter: 4
Exit: 4
Enter: 5
Exit: 5
我很困惑为什么在第一种情况下,当我递增迭代器时,它再次指向之前的映射元素 4?
取消对 map1.end()
的迭代器的引用会产生未定义的结果,而这正是您在最后一次循环迭代的 cout 中 运行ning it->first
时所做的。
在第一个变体中,您 运行 ++it
,达到 map1.end()
。从概念上讲,map1.end()
不指向任何元素,取消引用它可以提供任何随机结果(包括 SEGFAULT)。在您的情况下,它可能指向包含 4
.
的陈旧内存
在第二个变体中,您永远无法取消引用 map1.end()
,因为一旦到达容器末尾,循环条件就会退出。您总是在循环中打印出相同的元素。
另请注意上面的答案 - 擦除元素会使迭代器无效,因此两种变体仍然无效。
两个版本都是未定义的行为,后者似乎有效。
在这两种情况下,你增加一个已经失效的迭代器,
例如参见 [=12=]
后者的行为不同,因为 'enter' 和 'exit' 正在打印
相同的迭代器
这由 "iterate-erase" 惯用语解决,所有 STL 容器都支持
// C++11
auto iter = container.begin();
while( iter != container.end() )
{
if( SomeCondition() )
iter = container.erase(iter);
else
++iter;
}
这正是擦除 returns 迭代器的原因
注意关联容器,例如std::map
在 C++11
之前不支持这个
我在下面写这段代码,发现了这个奇怪的行为:
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<int, string> map1;
map1[1] = "Hello";
map1[2] = "Hello1";
map1[3] = "Hello2";
map1[4] = "Hello3";
map1[5] = "Hello4";
map<int, string>::iterator it;
for (it = map1.begin(); it != map1.end(); /*it++*/)
{
cout << "Enter: " << (int)(it->first) << endl;
if (it->first == 3)
map1.erase(it);
it++;
cout << "Exit: " << (int)(it->first) << endl;
}
return 0;
}
输出是:
Enter: 1
Exit: 2
Enter: 2
Exit: 3
Enter: 3
Exit: 4
Enter: 4
Exit: 5
Enter: 5
Exit: 4
当我仅在 for 循环中增加迭代器 it
时(检查注释迭代器),输出如下:
Enter: 1
Exit: 1
Enter: 2
Exit: 2
Enter: 3
Exit: 3
Enter: 4
Exit: 4
Enter: 5
Exit: 5
我很困惑为什么在第一种情况下,当我递增迭代器时,它再次指向之前的映射元素 4?
取消对 map1.end()
的迭代器的引用会产生未定义的结果,而这正是您在最后一次循环迭代的 cout 中 运行ning it->first
时所做的。
在第一个变体中,您 运行 ++it
,达到 map1.end()
。从概念上讲,map1.end()
不指向任何元素,取消引用它可以提供任何随机结果(包括 SEGFAULT)。在您的情况下,它可能指向包含 4
.
在第二个变体中,您永远无法取消引用 map1.end()
,因为一旦到达容器末尾,循环条件就会退出。您总是在循环中打印出相同的元素。
另请注意上面的答案 - 擦除元素会使迭代器无效,因此两种变体仍然无效。
两个版本都是未定义的行为,后者似乎有效。
在这两种情况下,你增加一个已经失效的迭代器,
例如参见 [=12=]
后者的行为不同,因为 'enter' 和 'exit' 正在打印
相同的迭代器
这由 "iterate-erase" 惯用语解决,所有 STL 容器都支持
// C++11
auto iter = container.begin();
while( iter != container.end() )
{
if( SomeCondition() )
iter = container.erase(iter);
else
++iter;
}
这正是擦除 returns 迭代器的原因
注意关联容器,例如std::map
在 C++11