These are two pieces of code that I ran under the C++11 standard. I expected the post-decrement of the iterator to produce the same effect, but these two pieces of code produce completely different results. Where is my understanding off?
list<int> L;
int main() {
L.push_back(0);
L.push_front(1);
auto it = L.begin();
for (int i = 2; i <= 5; i++) {
L.insert(it--, i);
}
for (auto num : L) {
printf("%d ", num);
}
// 2 5 0 4 1 3
}
list<int> L;
int main() {
L.push_back(0);
L.push_front(1);
auto it = L.begin();
for (int i = 2; i <= 5; i++) {
L.insert(it, i);
it--;
}
for (auto num : L) {
printf("%d ", num);
}
// 5 4 3 2 1 0
}
>Solution :
Consider exactly when the post-decrement happens. In the second case, obviously the insert happens, modifying the list itself. The iterator is still valid, pointing now at the second entry. Then the decrement is computed, moving the iterator to the first entry.
In the first case, however, the post-decrement "makes a copy" of the iterator, performs the decrement, and returns the previous version. That means that the new value of the iterator is computed before the insert happens, which is invalid since it already points at the first element. Note that the insert still happens correctly, because the post-decrement returns the original and still-valid iterator.
This is not about post- vs. pre- decrement behavior. It’s about when the side-effect of the decrement actually happens. See https://en.cppreference.com/w/cpp/language/eval_order, specifically
- When calling a function (whether or not the function is inline, and
whether or not explicit function call syntax is used), every value
computation and side effect associated with any argument expression,
or with the postfix expression designating the called function, is
sequenced before execution of every expression or statement in the
body of the called function.