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

Arm*_*yan 10 c++ iterator side-effects post-increment c++03

根据这个非常高度推崇的答案,迭代一组擦除一些元素的规范方法如下:

for (it = mySet.begin(); it != mySet.end(); ) {
    if (conditionToDelete(*it)) {
        mySet.erase(it++);
    }
    else {
        ++it;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

itToDelete = it++;
mySet.erase(itToDelete);
Run Code Online (Sandbox Code Playgroud)

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

mySet.erase(it++);
Run Code Online (Sandbox Code Playgroud)

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

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

标准的行情非常受欢迎.

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

Sha*_*our 11

这不是C++ 03中的未定义行为,因为在评估所有函数参数之后存在一个序列点.

最接近C++ 03且公开可用的标准草案是N1804,之前我没有找到草案标准的公开版本,但关于序列点维基百科文章使用了C++ 98c ++ 03作为参考,短语与N1804的以下段落一致.

1.9 程序执行16节中说(强调我的未来):

在调用函数时(无论函数是否为内联函数),在评估函数体中任何表达式或语句之前发生的所有函数参数(如果有)之后,都会有一个序列点.[...]

稍后在章节5.2.2 函数调用8段中说:

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