使用std::cout对参数求值的顺序

Order of evaluation of arguments using std::cout

本文关键字:顺序 std cout 使用 参数      更新时间:2023-10-16

大家好,我今天偶然发现了这段代码,我很困惑到底发生了什么,更具体的是按什么顺序:

代码:

#include <iostream>
bool foo(double & m)
{
    m = 1.0;
    return true;
}
int main()
{
    double test = 0.0;
    std::cout << "Value of test is : t" << test << "tReturn value of function is : " << foo(test) <<  "tValue of test : " << test << std::endl;
    return 0;
}

输出为:

Value of test is :      1       Return value of function is : 1 Value of test : 0

看到这一点,我会假设在调用函数之前会打印出最正确的参数。所以这是从右到左的评价??不过,在调试过程中,函数似乎是在输出之前调用的,这正是我所期望的。我正在使用Win7和MSVS2010。感谢您的帮助!

表达式中元素的求值顺序是未指定的(除了一些非常特殊的情况,例如&&||运算符以及三元运算符,它们引入了序列点(;因此,不能保证test将在foo(test)(修改它(之前或之后被评估。

如果您的代码依赖于特定的求值顺序,那么获得它的最简单方法是将表达式拆分为几个单独的语句。

这个问题的答案在C++17中发生了变化。

重载运算符的评估现在按照与内置运算符相同的方式排序(C++17[over.match.oper]/2(。

此外,<<>>和下标运算符现在将左操作数排序在右操作数之前,并且函数调用的后缀表达式在参数的求值之前排序。

(其他二进制运算符保留其先前的排序,例如+仍然未排序(。

因此,问题中的代码现在必须输出Value of test is : 0 Return value of function is : 1 Value of test : 1。但"不要这样做"的建议仍然是合理的,因为每个人都需要一段时间才能更新到C++17。

未指定评估顺序。它不是从左到右,从右到左,或者其他任何东西。

不要这样做。

未指定评估顺序,请参阅http://en.wikipedia.org/wiki/Sequence_point

这与操作员的示例+示例相同:

考虑两个函数f()g()。在C和C++中,+运算符不与序列点相关联,因此在表达式f()+g()中,可能首先执行f()g()

c++引用很好地解释了为什么永远不应该这样做(导致UB或未定义的行为(https://en.cppreference.com/w/cpp/language/operator_incdec

#include <iostream>
int main()
{
    int n1 = 1;
    int n2 = ++n1;
    int n3 = ++ ++n1;
    int n4 = n1++;
//  int n5 = n1++ ++;   // error
//  int n6 = n1 + ++n1; // undefined behavior
    std::cout << "n1 = " << n1 << 'n'
              << "n2 = " << n2 << 'n'
              << "n3 = " << n3 << 'n'
              << "n4 = " << n4 << 'n';
}

票据

由于所涉及的副作用,内置增量和减量必须小心使用运算符,以避免由于违反排序规则。


在与排序规则相关的部分中,您可以阅读以下内容:

未定义的行为:

1( 如果标量对象的副作用相对于同一标量对象的另一个副作用是未排序的,则行为是未定义的。

i = ++i + 2;       // undefined behavior until C++11
i = i++ + 2;       // undefined behavior until C++17
f(i = -2, i = -2); // undefined behavior until C++17
f(++i, ++i);       // undefined behavior until C++17, unspecified after C++17
i = ++i + i++;     // undefined behavior

2( 如果标量对象上的副作用相对于使用同一标量对象的值的值计算是未排序的,则行为是未定义的。

cout << i << i++; // undefined behavior until C++17
a[i] = i++;       // undefined behavior until C++17
n = ++i + i;      // undefined behavior