【问题标题】:Order of evaluation in C++ function parametersC++ 函数参数中的求值顺序
【发布时间】:2011-02-25 11:13:38
【问题描述】:

如果我们有三个这样组成的函数(foo、bar 和 baz)......

foo(bar(), baz())

C++ 标准是否保证 bar 将在 baz 之前被评估?

【问题讨论】:

    标签: c++ standards


    【解决方案1】:

    不,没有这样的保证。根据 C++ 标准,它是未指定的。

    Bjarne Stroustrup 也在“C++ 编程语言”第 3 版第 6.2.2 节中明确表示,并有一些推理:

    更好的代码可以在 没有表达限制 评价顺序

    虽然从技术上讲,这指的是同一节的前面部分,它说表达式部分的评估顺序也是未指定的,即

    int x = f(2) + g(3);   // unspecified whether f() or g() is called first
    

    【讨论】:

    • 是的,但是如果表达式评估顺序是 STRICT,则可以编写更好的代码(=更清洁),这通常比代码生成重要得多。看这个例子:stackoverflow.com/questions/43612592/… 那么,Stroustrup。
    • 如果订购很重要,您可以自己进行排序。否则,总是会为并不总是(很少?)重要的事情付出代价。我认为不为你不使用的东西付费的政策是大多数 C++ 程序员唯一同意的。
    • 不应该是“未指定行为”而不是“未定义”吗?
    • @GoodDeeds 在 C++17 之前,如果函数对同一内存位置造成副作用,则行为未定义。在 C++17 之后,它是未指定的。
    • @ChrisDodd 由于使用“未定义”和“未指定”这个词而拒绝接受的答案对我来说就像恶意迂腐......我没有说这是“未定义的行为”,否则“未定义”和“未指定”似乎是同义词?无论如何,提议对答案进行编辑将是讨论此问题的一种更有效的方式
    【解决方案2】:

    来自[5.2.2]函数调用,

    参数的评估顺序未指定。参数表达式求值的所有副作用在输入函数之前生效。

    因此,不能保证bar()会在baz()之前运行,只有bar()baz()会在foo之前被调用。

    另请注意 [5] 表达式:

    除非另有说明 [例如&&||] 的特殊规则、单个运算符的操作数和单个表达式的子表达式的求值顺序以及副作用发生的顺序是未指定的。

    因此,即使您在foo(bar() + baz()) 中询问bar() 是否会在baz() 之前运行,顺序仍然未指定。

    【讨论】:

    • [5.14] 逻辑与运算符中的“特殊说明”示例:“与& 不同,&& 保证从左到右的评估:如果第一个操作数不评估第二个操作数操作数是false。”
    【解决方案3】:

    没有指定 bar() 和 baz() 的顺序 - 标准中唯一说的是它们都将在 foo() 被调用之前进行评估。来自 C++ 标准,第 5.2.2/8 节:

    参数的评估顺序 未指定。

    【讨论】:

    • 至少在 foo() 之前对它们进行评估的事实有点让人放心。
    • @BillKotsias 该标准还规定函数调用不能重叠(即实现不能运行bar的第1行,然后baz的第1行,然后bar的第2行,等等.),这也很好。 :-)
    【解决方案4】:

    C++17 为在 C++17 之前未指定的运算符指定求值顺序。看问题What are the evaluation order guarantees introduced by C++17? 但是注意你的表情

    foo(bar(), baz())
    

    仍有未指定的评估顺序。

    【讨论】:

      【解决方案5】:

      在C++11中,相关的文字可以在8.3.6 Default arguments/9找到(重点是我的)

      每次调用函数时都会评估默认参数。 函数参数的求值顺序未指定。因此,函数的参数不应在默认参数中使用,即使它们没有被评估。

      C++14 标准也使用相同的措辞,可在the same section 下找到。

      【讨论】:

        【解决方案6】:

        正如其他人已经指出的那样,该标准并未就此特定场景的评估顺序提供任何指导。这个评估顺序然后留给编译器,编译器可能有保证。

        请务必记住,C++ 标准实际上是一种指导编译器构建汇编/机器代码的语言。标准只是方程式的一部分。如果标准模棱两可或具体实现定义,您应该求助于编译器并了解它如何将 C++ 指令翻译成真正的机器语言。

        因此,如果求值顺序是一项要求,或者至少很重要,并且不需要与交叉编译器兼容,那么请研究一下您的编译器最终将如何将这些组合在一起,您的答案最终可能就在那儿。请注意,编译器将来可能会更改其方法

        【讨论】:

          猜你喜欢
          • 2019-10-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多