为什么mySet.erase(it ++)不是未定义的行为,或者是它?

时间:2013-10-23 15:35:40

标签: c++ iterator c++03 post-increment side-effects

Accordint to this quite highly upvoted answer,循环删除一些元素的规范方法如下:

for (it = mySet.begin(); it != mySet.end(); ) {
    if (conditionToDelete(*it)) {
        mySet.erase(it++);
    }
    else {
        ++it;
    }
}

这当然是C ++ 03设置擦除不返回迭代器的结果。否则可以写it = mySet.erase(it);很明显可以写

itToDelete = it++;
mySet.erase(itToDelete);

这个问题不是关于如何在迭代时删除元素。问题是为什么以下行显然导致未定义的行为。

mySet.erase(it++);

起初我确信这必须是UB,因为我在考虑后增量方面做错了。这是一种常见(但错误的)方式,将预增量视为在评估的其余部分之前发生,并且后增量发生在AFTER之后。当然,这是错误的。后增量和前增量都有增加变量的副作用。区别在于这些表达的价值。

尽管如此,据我所知,C ++标准(至少是C ++ 03标准)没有明确说明后增量的副作用何时发生。因此,除非我们保证如果作为后增量表达式的函数参数在进入函数体之前具有的副作用,那么这不应该是UB吗?究竟是什么(标准方面),如果有的话,禁止在迭代器在函数体内失效后发生的++副作用?

非常欢迎来自标准的行情。

为了一个参数,我们还假设set的迭代器是一个内置类型,这实际上是operator ++,而不是重载的operator-function

1 个答案:

答案 0 :(得分:11)

这不是 C ++ 03 中的undefined behavior,因为在评估完所有函数参数后会有序列点

最接近C ++ 03并且公开可用的标准草案是N1804,之前我没有找到标准草案的公开版本,但Wikipedia article on sequence points使用了< em> C ++ 98 c ++ 03 作为参考,这些短语与 N1804 中的段落一致。

1.9 部分 16 16 中说明(强调我的前进):

  

当调用函数时(函数是否为内联函数),在执行任何表达式或语句之前,在评估所有函数参数(如果有)之后有一个序列点在函数体中。 [...]

以及稍后部分5.2.2 函数调用 8 说:

  

参数的评估顺序未指定。 参数表达式评估的所有副作用在输入函数之前生效。后缀表达式和参数表达式列表的评估顺序未指定。