C ++函数参数中的求值顺序


90

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

foo(bar(), baz())

C ++标准是否可以保证在baz之前对bar进行评估?

Answers:


102

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

Bjarne Stroustrup还在“ The C ++ Programming Language”第三版第6.2.2节中明确指出了这一点,并提出了一些理由:

在没有表达式计算顺序限制的情况下,可以生成更好的代码

尽管从技术上讲,这是指同一部分的较早部分,该部分表示表达式的各部分的求值顺序也未指定,即

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

我可以在8分钟内接受这个答案...我想我会坚持一段时间!
克拉克·盖贝尔

4
是的,但是如果表达式求值顺序为STRICT,则更好的代码可以写(= cleaner)(通常比代码生成重要得多)。参见以下示例:stackoverflow.com/questions/43612592/…因此,Stroustrup。
Bill Kotsias '17

1
如果订购很重要,您可以自己进行排序。否则,总会因并非总是(很少?)重要的事情而产生成本。我认为不付钱就不用的政策是大多数C ++程序员唯一同意的事情。
tweej

3
难道不是“未指明的行为”而不是“未定义的行为”吗?
GoodDeeds

1
@ChrisDodd否决了接受的答案,因为使用了“ undefined”和“ unspecified”这两个词对我来说就像是恶意的ant脚……我不是说这是“ undefined behavior”,否则似乎是“ undefined”和“ unspecified”同义的?无论如何,建议对答案进行编辑将是讨论这一问题的一种更有效率的方式
Eli Bendersky '18

20

bar()和baz()没有指定的顺序-标准仅说明它们将在调用foo()之前进行评估。根据C ++标准的第5.2.2 / 8节:

参数的评估顺序未指定。


4
至少在foo()之前对它们进行求值的事实令人放心。
比尔·科西亚斯

1
@BillKotsias该标准还说函数调用不能重叠(即,一个实现不能运行的第1行bar,不能运行的第1行baz,再运行的第2行bar,等等),这也很好。:-)
melpomene

20

从[5.2.2]函数调用中,

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

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

还请注意[5]表达式中的内容:

除非另有说明[例如特殊规则&&||],个体经营者和单个表达式的子表达式,并且其中的副作用发生的顺序的操作数的计算顺序,是不确定的。

所以即使你在问是否bar()将之前运行baz()foo(bar() + baz()),订单仍然是不确定的。


4
来自[5.14]逻辑AND运算符的“特殊说明”的示例:“与其他不同&&&保证从左到右的求值:如果第一个操作数为,则不求第二个操作数false。”
丹尼尔·特雷比安


2

在C ++ 11中,相关文本可以在8.3.6默认参数/ 9(强调我的)中找到。

每次调用函数时都会评估默认参数。函数参数的求值顺序不确定。因此,即使未对函数的参数进行求值,也不得在默认参数中使用该函数的参数。

C ++ 14标准也使用相同的语言,可在同一部分中找到。


0

正如其他人已经指出的那样,该标准并未对此特定方案的评估顺序提供任何指导。然后,将评估的顺序留给编译器,并且编译器可能会有保证。

重要的是要记住,C ++标准实际上是一种指示编译器构造汇编/机器代码的语言。标准只是方程式的一部分。如果该标准含糊不清或专门为实现定义,则应转向编译器并了解其如何将C ++指令转换为真正的机器语言。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.