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

别说谁变了你拦得住时间么 提交于 2019-12-08 15:39:05

问题


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;
    }
}

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++);

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.

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?

Quotes from the standard would be very much welcome.

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


回答1:


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

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.

In section 1.9 Program execution paragraph 16 says (emphasis mine going forward):

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. [...]

and later on in section 5.2.2 Function call paragraph 8 says:

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.



来源:https://stackoverflow.com/questions/19546124/why-isnt-myset-eraseit-undefined-behavior-or-is-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!