为什么 "L.insert(it--, i);" 的行为与 "L.insert(it, i); it--;" 不同?

Why does "L.insert(it--, i);" behave differently from "L.insert(it, i); it--;"?

这是我运行在C++11标准下的两段代码。我期望迭代器的 post-decrement 产生相同的效果,但是这两段代码产生完全不同的结果。我的理解哪里不对?

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
}

您的代码调用了未定义的行为。

The begin iterator is not decrementable and the behavior is undefined if --container.begin() is evaluated.

https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator

因此,任何事情都有可能发生。

L.insert(it, i);
it--;

这会在 it 之前插入一个节点,然后 it 向后移动到插入的节点。

L.insert(it--, i);

交换操作顺序:它向后移动迭代器,然后 insert() 被调用。没有要移回的节点,因此会导致未定义的行为。

考虑 post-decrement 发生的时间。在第二种情况下,显然插入发生了,修改了列表本身。迭代器仍然有效,现在指向第二个条目。然后计算减量,将迭代器移动到第一个条目。

然而,在第一种情况下,post-decrement“复制”迭代器,执行递减,returns 以前的版本。这意味着迭代器的新值是在 before 插入发生之前计算的,这是无效的,因为它已经指向第一个元素。请注意,插入仍然正确发生,因为 post-decrement returns 原始迭代器和 still-valid 迭代器。

这与 post- 与预递减行为无关。这是关于减量的 side-effect 实际发生的时间。见https://en.cppreference.com/w/cpp/language/eval_order,具体

  1. 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.