如果在 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?

是的。擦除将使您现在所在的迭代器无效,这将使它的后续增量成为未定义的行为 - 但没有后续增量,因为您无条件地 breaking。


尽管不必遍历每个元素直到找到 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 迭代器之前结束。