C++ cout行为/执行顺序

3
我正在查看CPPInstitute的CPA-21-01考试的一些示例问题,但对第11题有点困惑。 它陈述如下:
#include <iostream>

using namespace std;

class A {
public:
    A() {
        a.a = a.b = 1;
    }
    struct { int a,b; } a;
    int b(void);
};

int A::b(void)
{
    int x=a.a;
    a.a=a.b;
    a.b=x;
    return x;
}

int main(void) {
    A a;
    a.a.a = 0;
    a.b();
    cout << a.b() << a.a.b << endl;

    return 0;
}

这个程序会导致编译错误。

B. 10

C. 01

D. 11

可以将其简化为更小的例子:

int swap_and_return(int& a, int& b) {
    std::swap(a,b);
    return a;
}

int main() {

    int a = 0;
    int b = 1;

    cout << swap_and_return(a,b) << a << endl;

    return 0;
}

到目前为止还不错;答案键说是B。
假设你选择了D。
根据this,执行顺序是任意的:
15)在函数调用中,每个参数的值计算和初始化的副作用与任何其他参数的值计算和副作用的顺序不确定。
已经有一个类似的问题here 我认为cout行可以翻译成cout.operator<<(a.b()).operator<<(a.a.b);,这意味着应该有一个序列点并且行为应该是确定的?
实际上,得到以下结果:
MS cl.exe,Debug:10
MS cl.exe,Release:11 GCC,C++11:11

Clang:11

不用说,我现在有点困惑了,因为他们说答案是B,但实际上执行顺序似乎是任意的。

请问有人能解释一下我关于执行顺序的看法是否正确,以及应该是什么顺序吗?

谢谢!


1
C++17 修复了这个问题。 - Eljay
这个问题有什么可耻的地方,值得在几分钟内被投两个负票? - namezero
公平地说,这段代码的认知负荷非常高(也就是说,很难阅读和理解),人们可能希望你将其简化为更适合 Stack Overflow 的 [MCVE]。现在的容忍度/耐心相当低。尽管如此,个人认为这并不值得一个踩。毫无疑问,问题本身是有意义的,我想没有人会反对我的观点。 - Lightness Races in Orbit
哦,还有很多关于序列点的问题被膝反应式地投下了负票,因为(a)我们收到的大部分问题都是相同的,而且(b)这些问题由糟糕的教授向学生提出的非常愚蠢的代码所代表。但是(c)这不是你的错,而且(d)这个问题本身也不是那种情况的一个实例。 - Lightness Races in Orbit
@LightnessRacesinOrbit 谢谢,我已经添加了一个更简单的示例来演示手头的问题。 - namezero
与您在各处和SO上找到的类似示例不同的是,此示例中的副作用发生在函数调用内部,而不是直接在参数评估中。 - namezero
1个回答

4

在C++17之前,你是正确的,这个问题没有提供正确答案。

但自那时以来,答案是确定的


2
谢谢。我现在明白了,自从C++17以来,求值顺序将与运算符的结合性匹配。我会写下更新问题的内容,因为在17标准之前似乎没有合适的答案,而且他们的答案是错误的。 - namezero
只是跟进一下,因为C++17意味着所有操作符链接的副作用都保证按照操作符的结合性顺序进行评估,而不是之前吗? - namezero
1
@namezero 我认为是这样,但是请在链接的问题上询问以获得澄清。 - Lightness Races in Orbit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接