【问题标题】:Why isn't mySet.erase(it++) undefined behavior, or is it?为什么 mySet.erase(it++) 不是未定义的行为,或者是?
【发布时间】:2013-11-01 23:47:20
【问题描述】:

Accordint to this quite highly upvoted answer,遍历集合擦除某些元素的规范方法如下:

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

这当然是 C++03 的 set erase 没有返回迭代器的结果。不然可以写it = mySet.erase(it); 也很明显可以写

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

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

mySet.erase(it++);

起初我确定这一定是 UB,因为我对后增量的看法是错误的。这是一种常见(但错误)的方式,将预增量视为在其余评估之前发生,而后增量发生在之后。当然,这是错误的。 postincrement 和 preincrement 都有增加变量的副作用。区别在于这些表达式的值。

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

非常欢迎引用标准。

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

【问题讨论】:

  • 标准不要求在控制流进入被调用函数的主体之前评估所有函数参数吗?
  • @H2CO3:评估某事是否涉及所有副作用的发生?
  • 我很确定确实如此,但我正在检查标准。

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


【解决方案1】:

这不是 C++03 中的 undefined behavior,因为在计算所有函数参数之后有一个 序列点

最接近 C++03 且可公开获得的标准草案是 N1804,我找不到之前的标准草案的公开版本,但 Wikipedia article on sequence points 使用 C+ +98c++03 作为参考,短语与 N1804 中的以下段落一致。

1.9 部分程序执行16段说(强调我的前进):

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

之后在5.2.2 部分函数调用段落8说:

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

【讨论】:

    猜你喜欢
    • 2011-05-05
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多