为什么mySet.erase(it ++)不是未定义的行为,或者是它? [英] Why isn't mySet.erase(it++) undefined behavior, or is it?

查看:192
本文介绍了为什么mySet.erase(it ++)不是未定义的行为,或者是它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Accordint 这个非常高度响应的答案 ,迭代一组擦除一些元素的规范方法如下:

Accordint to this quite highly upvoted answer, the canonical way to iterate through a set erasing some elements is the following:

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

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

This, of course, is a result of C++03's set erase not returning an iterator. Otherwise one could write it = mySet.erase(it); It is also obvious that one can write

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

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

This question is not about how to delete elements while iterating. The question is why does the following line apparently not result in undefined behavior.

mySet.erase(it++);

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

At first I was sure this had to be UB, because I was thinking in the wrong way about postincrement. It is a common (but wrong) way to think of pre-increment as happening BEFORE rest of evaluation, and postincrement happening AFTER. Of course, this is wrong. Both postincrement and preincrement have the side effect of incrementing the variable. The difference is the value of those expressions.

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

That said, as far as I can remember, the C++ standard (at least the C++03 one) does not specify exactly when the side effect of postincrement will take place. So, unless we have a guarantee that if a function argument which is a postincrement expression will have its side effects in place before entering the function body, shouldn't this be UB? What exactly (standards-wise), if anything, prohibits the side-effect of it++ taking place after the iterator has been invalidated inside the function body?

标准引用非常欢迎。

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

For an argument's sake let's also suppose that set's iterator is a built in type and this is actually operator ++, not the overloaded operator-function

推荐答案

这不是 C ++ 03 中的/en.wikipedia.org/wiki/Undefined_behavior\"rel =nofollow>未定义的行为,因为毕竟有一个序列点函数参数被评估。

This is not undefined behavior in C++03 because there is a sequence point after all the function arguments are evaluated.

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

The draft standard that is closest to C++03 and that is publicly available is N1804, there is no public version of the draft standard from before that I can find but the Wikipedia article on sequence points used C++98 and c++03 as references and the phrases are consistent with the paragraphs below from N1804.

1.9 程序执行 16 表示(强调我的前进):


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

When calling a function (whether or not the function is inline), there is a sequence point after the evaluation of all function arguments (if any) which takes place before execution of any expressions or statements in the function body. [...]

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


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

The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect before the function is entered. The order of evaluation of the postfix expression and the argument expression list is unspecified.

这篇关于为什么mySet.erase(it ++)不是未定义的行为,或者是它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆