如果在 foreach 循环之后立即爆发,修改 unordered_set 是否定义明确?
Is it well-defined to modify an unordered_set inside a foreach loop if one breaks out immediately after?
考虑以下程序。中间的循环尝试用另一项恰好替换一项,然后跳出循环。
#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);
}
上面的代码定义好了吗?
Is the code above well-defined?
是的。擦除将使您现在所在的迭代器无效,这将使它的后续增量成为未定义的行为 - 但没有后续增量,因为您无条件地 break
ing。
尽管不必遍历每个元素直到找到 1
,但您可以尝试擦除它并查看是否有任何作用:
if (foo.erase(1)) {
foo.insert(4);
}
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
是一个神奇的函数,它会做一些事情来找到开始迭代器,其细节在这里无关紧要。 (此外,__
前缀名称仅用于说明目的)。
由于您的代码是使用上述转换定义的,因此在定义时没有使用它。
标准中的大部分内容都不是这样明确的;这个真的是。
甚至还有上述改造造成的bug。例如,如果 target
具有不是表达式结果的临时对象,则它们的生命周期在创建 __start
迭代器之前结束。
考虑以下程序。中间的循环尝试用另一项恰好替换一项,然后跳出循环。
#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);
}
上面的代码定义好了吗?
Is the code above well-defined?
是的。擦除将使您现在所在的迭代器无效,这将使它的后续增量成为未定义的行为 - 但没有后续增量,因为您无条件地 break
ing。
尽管不必遍历每个元素直到找到 1
,但您可以尝试擦除它并查看是否有任何作用:
if (foo.erase(1)) {
foo.insert(4);
}
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
是一个神奇的函数,它会做一些事情来找到开始迭代器,其细节在这里无关紧要。 (此外,__
前缀名称仅用于说明目的)。
由于您的代码是使用上述转换定义的,因此在定义时没有使用它。
标准中的大部分内容都不是这样明确的;这个真的是。
甚至还有上述改造造成的bug。例如,如果 target
具有不是表达式结果的临时对象,则它们的生命周期在创建 __start
迭代器之前结束。