如果紧接在一个foreach循环中修改了unordered_set,是否定义明确?

时间:2018-07-24 18:48:01

标签: c++ c++11 iterator unordered-set

请考虑以下程序。中间的循环尝试将另一项恰好替换为另一项,然后跳出循环。

#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 个答案:

答案 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迭代器之前结束。