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

Why isn't mySet.erase(it++) undefined behavior, or is it?

本文关键字:还是 未定义 erase mySet it++ 为什么      更新时间:2023-10-16

根据这个相当高投票的答案,迭代一个集合擦除一些元素的规范方法如下:

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,因为我对后期增量的想法是错误的。这是一种常见(但错误)的方式,将前增量视为在评估的其余部分之前发生,而后增量发生在评估之后。当然,这是错误的。后增量和预递增都有递增变量的副作用。区别在于这些表达式的值。

也就是说,据

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

非常

欢迎引用标准。

为了参数的缘故,我们还假设set的迭代器是内置类型,这实际上是运算符++,而不是重载的运算符函数

这不是 C++03 中的未定义行为,因为在计算所有函数参数后都有一个序列点

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

在第1.9节"计划执行"中,第16段说(强调我的前进):

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

后来在第 5.2.2 节中函数调用8 段说:

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