请考虑以下程序。中间的循环尝试将另一项恰好替换为另一项,然后跳出循环。
#include <unordered_set>
#include <stdio.h>
int main(){
std::unordered_set<int> foo{1,2,3};
printf("Set Before:\n");
for (int x : foo)
printf("%d\n", x);
for (int x : foo) {
if (x == 1) {
foo.erase(1);
foo.insert(4);
break;
}
}
printf("Set After:\n");
for (int x : foo)
printf("%d\n", x);
}
上面的代码定义明确吗?
答案 0 :(得分:10)
上面的代码定义明确吗?
是的。擦除将使您当前正在使用的迭代器无效,这将使其后续的增量没有定义的行为-但是没有后续的增量,因为您无条件break
进行了迭代。
尽管可以不循环遍历每个元素直到找到1
,但可以尝试擦除它,看看是否有作用:
if (foo.erase(1)) {
foo.insert(4);
}
答案 1 :(得分:5)
for(type var:target)
循环被定义为等效于:
{
auto&& __target = target;
auto&& __start = __magic_begin(__target);
auto&& __finish = __magic_end(__target);
for (; __start != __finish; ++__start) {
type var = *__start;
__body_of_loop_here__
}
}
其中__magic_begin
是一个魔术函数,它可以执行一些操作来查找开始迭代器,此处的详细信息无关紧要。 (此外,__
前缀名称仅用于说明目的。
由于您的代码是通过上述转换定义的,因此无需定义即可。
标准中的大多数内容都不是很明确的。这真的是。
甚至还有由上述转换引起的错误。例如,如果target
的临时表达式不是表达式的结果,则它们的生命周期将在创建__start
迭代器之前结束。