C++ 如果一个foreach循环紧接着发生故障,那么修改foreach循环中的无序_集是否定义良好?

C++ 如果一个foreach循环紧接着发生故障,那么修改foreach循环中的无序_集是否定义良好?,c++,c++11,iterator,unordered-set,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)

考虑以下程序。中间的循环试图用一个其他项替换一个项,然后从循环中跳出。

#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);
}
#包括
#包括
int main(){
无序集foo{1,2,3};
printf(“设置在:\n之前”);
for(int x:foo)
printf(“%d\n”,x);
for(int x:foo){
如果(x==1){
foo.erase(1);
foo.插入(4);
打破
}
}
printf(“设置在:\n之后”);
for(int x:foo)
printf(“%d\n”,x);
}
上面的代码定义正确吗?

上面的代码定义得好吗

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


虽然不必在每个元素上循环,直到找到
1
,但您可以尝试擦除它,看看它是否有任何作用:

if (foo.erase(1)) {
    foo.insert(4);
}
for(类型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__
  }
}
其中
\uu magic\u begin
是一个神奇的函数,它做了一些事情来查找begin迭代器,这里的细节并不重要。(另外,
\uuuuu
前缀名称仅用于说明目的)

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

标准中的大多数内容都不是如此明确;这个真的很好


甚至还有由上述转换引起的bug。例如,如果
target
的临时变量不是表达式的结果,则它们的生存期在创建
\u start
迭代器之前结束。

将迭代器增加到已删除的条目,听起来似乎不是一个好的常规做法。在这种情况下,它很少(如果有任何区别),但是C++是基于类型的。在单个位置更改类型可能会对代码产生级联影响,因此最好在可能的情况下使用引用和非复制,这样您就可以在一个位置更改代码,并且仍然拥有最高效的代码。
std::find_如果
看起来更惯用(假设您真的必须进行线性搜索)。另外,是否有任何理由不使用同样在C++11中引入的
std::begin
std::end
来定义
\uuuuuu magic\u begin
\uuuuuuu magic\u end
?cppreference的页面上没有提到它们,尽管解释听起来几乎相同。@alterigel Yes。它从不调用
std::begin
,除非类型在
命名空间std
中。这是一种语言功能,它不依赖于
std
库。也有细微的区别,但主要是关于依赖倒置(库依赖于语言,语言不依赖于库)。