C++评估顺序

Poc*_*ets 3 c++ g++ c++11 clang++

我试图弄清楚C++ 11规范中是否有任何内容.以下代码的预期行为(此处GitHub链接):

struct Scalar {
    int data;

    Scalar(int x) : data(x) {}

    int get() {
        return data;
    }

    Scalar &square() {
        scale(data);
        return *this;
    }

    void scale(int rhs) {
        data *= rhs;
    }
};

int main() {
    Scalar v(3);

    v.square().scale(v.get());

    return v.data;
}
Run Code Online (Sandbox Code Playgroud)

这主要是因为发现它在g++和之间做了不同的事情clang++:

$ g++ --version
g++ (GCC) 6.2.1 20160830
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ clang++ --version
clang version 3.9.0 (tags/RELEASE_390/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

$ g++ -std=c++11 order_of_ops.cpp -o a.out && ./a.out; echo $?
27

$ clang++ -std=c++11 order_of_ops.cpp -o a.out && ./a.out; echo $?
81
Run Code Online (Sandbox Code Playgroud)

答案似乎应该是在n3242的§5.2.2§5.2.5中,但是我无法追踪具体的东西.

krz*_*zaq 8

如果我正确读取了内容,则代码的行为未指定.N3337 for C++ 11引用:

§1.9[intro.execution]/15

除非另有说明,否则对单个运算符的操作数和单个表达式的子表达式的评估是不确定的.[...]如果标量对象的副作用相对于同一标量对象的另一个副作用或使用相同标量对象的值的计算值未被排序,则行为未定义.

但接下来是

调用函数(包括其他函数调用)中的每个评估(在执行被调用函数的主体之前或之后没有特别排序)对于被调用函数的执行是不确定地排序的.9

9)换句话说,函数执行不会相互交错.

§5.2.2[expr.call]/8

[ 注意:后缀表达式和参数表达式的评估都是相对于彼此的无法排序的.在输入函数之前,对参数表达式评估的所有副作用进行排序(参见1.9).- 尾注 ]

因此,您的修改和不相关的读取Scalar::data是不确定的顺序.

话虽这么说,它可能会改变并在C++ 1z中得到很好的定义:

N4606§5.2.2[expr.call]/5

所述后缀表达式每个之前测序表达在表达式列表和任何默认参数.参数的初始化(包括每个相关的值计算和副作用)相对于任何其他参数的初始化是不确定的.

因此,在C++ 1z中你v.data应该等于81(如果我正确读取的话)

  • 在前C++ 11中,当我们讨论序列点时,每个函数调用之前和之后都有一个序列点.这将使表达式定义良好,但具有未指定的结果,具体取决于调用的顺序. (2认同)