11

我很难理解下面代码中的调用顺序。我期待看到下面的输出

    A1B2

虽然我可以看到我得到的输出是

    BA12

我认为调用std::cout<< b->fooA() << b->fooB() << std::endl相当于调用

  std::cout.operator<<( b->fooA() ).operator<< ( b->fooB() )

但我可以看到情况并非如此。你能帮助我更好地理解它是如何工作的以及它与全球的关系operator<<吗?这是这个序列中最后一次调用的吗?

#include <iostream>

struct cbase{
    int fooA(){
        std::cout<<"A";
        return 1;
    }
    int fooB(){
        std::cout <<"B";
        return 2;
    }
};

void printcbase(cbase* b ){
    std::cout << b->fooA() << b->fooB() << std::endl;
}

int main(){
    cbase b;
    printcbase( &b );
}
4

3 回答 3

10

编译器可以这样评估函数printcbase()

void printcbase(cbase* b ){
    int a = b->FooA();    // line 1
    int b = b->FooB();    // line 2
    std::cout << a;       // line 3
    std::cout << b;       // line 4
    stc::cout << std::endl;
}

或标记为 1 - 4 的行的许多排列中的一些。您只能保证第 1 行在第 3 行之前完成,第 2 行在第 4 行之前完成(当然第 3 行在第 4 行之前)。标准并没有说更多,实际上您可以期望使用不同的 C++ 编译器得到不同的结果。

于 2013-02-11T10:25:53.957 回答
6

的执行顺序<<已明确定义,但 C++ 中未定义子表达式的求值顺序。本文和 C 代码示例说明了您提到的问题。

BA12并且AB12都是正确的。在以下代码中:

std::cout<< b->fooA() << b->fooB()

1将出现在之前,2A可能出现在之前或之后,B因为编译器不承诺它是否会评估fooAfooB首先评估。

于 2013-02-11T10:53:55.660 回答
4

移位运算符是左结合的;a << b << c读作(a << b) << c,表示如果a是具有用户定义成员的类型operator<<(并返回该类型),则表达式读作a.operator<<(b).operator<<(c)。如果改为使用 free operator<<,则读取为operator<<(operator<<(a, b), c).

所以 的 求值a << b在 的求值之前排序,但和(a << b) << c的求值之间没有顺序依赖关系:bc

a << b << c[1]
|         |
a << b[2] |
|    |    c[5]
a[3] b[4]

如果我们像上面那样对副作用进行编号,那么副作用可以按以下顺序排列:

54321
53421
45321
43521
43251
35421
34521
34251
于 2013-02-11T10:54:08.420 回答