【问题标题】:behavior of --it and it-- in [duplicate]--it 和 it-- 在 [重复] 中的行为
【发布时间】:2015-02-02 03:03:53
【问题描述】:

在函数调用上下文中it++++it 的行为的解释是什么——更具体地说,对于函数iter_swap?让我感到困惑的是,以下代码中的 call 2call 4 似乎是 交换元素,而 call 3并且调用 5 交换元素失败。我期待相反的结果,但是,我假设函数参数的一个条目将在另一个之前执行。从输出看,情况似乎并非如此。

那么,出于好奇,这种行为是否已定义?我如何理解事物的执行顺序?谢谢!

#include <iostream>
#include <vector>
#include <algorithm>
int main(void) {
    vector<int> a;
    a.push_back(1);
    a.push_back(2);

    vector<int>::iterator it_a, it_b;
    it_a = a.begin();
    it_b = it_a + 1;

    cout << *it_a << " " << *it_b << endl;
    // call 1
    iter_swap(it_a, it_b);
    cout << *it_a << " " << *it_b << endl;
    // call 2
    iter_swap(it_a, it_a++);
    cout << *--it_a << " " << *it_b << endl;
    // call 3
    iter_swap(it_a, ++it_a);
    cout << *--it_a << " " << *it_b << endl;
    // call 4
    iter_swap(it_a++, it_a);
    cout << *--it_a << " " << *it_b << endl;
    // call 5
    iter_swap(++it_a, it_a);
    cout << *--it_a << " " << *it_b << endl;

    return 0;
}

输出:

1 2
2 1
1 2
1 2
2 1
2 1

【问题讨论】:

  • 未指定参数的求值顺序,且参数列表中没有序列点,因此您的函数调用导致undefined behavior

标签: c++ iterator post-increment pre-increment


【解决方案1】:

这些示例中的大多数都没有定义行为(调用 1 是唯一的例外)。函数参数的求值是无序的,这意味着它们的求值顺序是未指定的,因此在调用函数时operator++ 的副作用是否已经影响到另一个参数是未定义的。使用不同的编译器,您可以获得不同的结果,并且两者都完全符合标准。

附录:我相信对语义的一些解释是有序的。

在 C++11 之前,我会在这里谈论序列点,但是标准语言已经更改为更清晰,没有太大变化。因此,我将讨论顺序操作

通常,C++11 中的操作在时间上是部分排序的。也就是说,可以对两个操作(我们称它们为O和P)进行排序,使得OP之前排序,O在P之后排序,或者O和 P 是不确定排序的,或者 O 和 P 是未排序的

前两个很简单:如果 O 排序在 P 之前,那么它的所有影响必须在 P 被评估时已经发生,如果 O 排序在 P 之后,那么当 O 出现时,P 的所有影响都已经出现。

至于其他两个:如果 O 和 P 是不定序的,那么要么 O 的所有效果出现在 P 被评估之前,或者 P 的所有效果出现在 O 被评估之前。如果它们是未排序的,那么这是一个很好的混搭:O 的一些效果可能出现在 P 的一些效果之前,同时 P 的一些效果可能出现在 O 的所有效果之前——实际上,评估O 和 P 可能重叠。

这必须在优化的上下文中看到:优化编译器喜欢重新排列代码以使其运行得更快。在排序方面的部分规范允许他们做更多的事情——也许 O 有一个对评估 P 有用的中间结果,诸如此类。例如,如果您考虑一个大型算术表达式,不难看出在有限数量的寄存器存在的情况下,宽松的排序如何有助于向量化。

那么,你的例子在哪里?

在 C++11 的 1.9 (15) 节中,提到“与不同参数表达式相关的值计算和副作用是unsequenced.”所以你在这里很深,与龙一起游泳。

【讨论】:

  • 更糟糕的是,我们不仅有未指定的行为,还有未定义的行为。请记住,向量迭代器可能是一个普通指针。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-29
  • 1970-01-01
  • 2021-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-07
相关资源
最近更新 更多