代码之家  ›  专栏  ›  技术社区  ›  merlin2011

如果foreach循环中的无序集在紧接着发生后立即发生,那么修改它是否定义得很好?

  •  4
  • merlin2011  · 技术社区  · 7 年前

    考虑下面的程序。中间的循环试图用另一个项替换一个项,然后中断循环。

    #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);
    }
    

    上面的代码定义好了吗?

    2 回复  |  直到 7 年前
        1
  •  10
  •   Barry    7 年前

    上面的代码定义好了吗?

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


    尽管不是在每个元素上循环直到找到 1 ,你可以试着抹掉它,看看它是否起到了什么作用:

    if (foo.erase(1)) {
        foo.insert(4);
    }
    
        2
  •  5
  •   Yakk - Adam Nevraumont    7 年前

    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 是一个神奇的函数,它可以做一些事情来找到begin迭代器,其细节在这里无关紧要(同时, __ 带前缀的名称仅用于说明目的)。

    由于您的代码是用上面的转换定义的,所以它是在没有转换的情况下定义的。

    标准中的大多数东西都不是这样明确的,这一点是真的。

    甚至还有由上述转换引起的错误。例如,如果 target 具有不是表达式结果的临时对象,它们的生命在 __start 迭代器被创建。