逗号操作符没有副作用

Is comma operator free from side effect?

本文关键字:副作用 操作符      更新时间:2023-10-16

例如:

c += 2, c -= 1

c += 2总是先求值,第二个表达式c-= 1中的c总是从表达式c += 2更新的值,这是真的吗?

是的,只要该逗号是非重载的逗号操作符,就可以得到标准的保证。引用n3290§5.18:

逗号操作符从左到右分组。


表达式:> <代码> code>表达式,赋值表达式

用逗号分隔的一对表达式从左到右求值;左边的表达式是一个废弃的-值表示(条款5)83。与左表达式相关的每个值计算和副作用与右表达式相关的每个值计算和副作用之前排序。类型结果的值是右操作数的类型和值;结果是相同的值类别如果右操作数为左值和位域,则为位域

和相应的脚注:

83然而,重载逗号操作符的调用是普通的函数调用;因此,为其实参的求值表达式是相对于其他表达式的未排序的(见1.9)。

对于非重载的逗号操作符,这里只保存

函数参数之间的operator,不是逗号操作符。此规则也不适用。

对于c++ 03,情况类似:

逗号操作符从左到右分组。


表达式:> <代码> code>表达式,赋值表达式

用逗号分隔的一对表达式从左到右求值,左边表达式的值为丢弃。左值到右值(4.1)、数组到指针(4.2)和函数到指针(4.3)的标准转换表达式不应用表达式表达式。左表达式的所有副作用(1.9),除了临时变量的销毁(12.2)在对正确表达式求值之前执行。类型和结果的值为右操作数的类型和值;如果右操作数为,则结果为左值。

的限制是相同的:不适用于重载的逗号操作符或函数参数列表。

是的,逗号操作符保证语句按照从左到右的顺序求值,返回值是求值后最右边的语句。

但是,请注意,在某些上下文中,逗号不是逗号操作符。例如,对于函数参数列表,上面的内容是不能保证的。

是的,在c++中,逗号操作符是一个序列点,这些表达式将按照它们被写入的顺序计算。见当前工作草案c += 2, c -= 1:

[snip]从左到右求值。(剪)

我觉得你的问题对你所说的"副作用"缺乏解释。c++中的每个语句都允许有副作用,重载的逗号操作符也是如此。

为什么你写的语句在函数调用中无效?

都是关于序列点的。在c++和C中,禁止在两个序列点之间修改值两次。如果您的示例真正使用c += 2, c -= 1,则每个自赋值都在其自己的序列点内。如果像这样使用foo(c += 2, c -= 1),则计算顺序未定义。我实际上不确定第二种情况是否是未定义的行为,因为我不知道参数列表是一个还是多个序列点。我应该问一个问题。

应该总是从左到右求值,因为这是逗号操作符的定义:链接

你有两个问题。

第一个问题:"逗号操作符没有副作用吗?"

这个问题的答案是否定的。逗号操作符自然有助于编写有副作用的表达式,故意编写有副作用的表达式是操作符通常用于的目的。例如,在foo((c += 2, c -= 1))中,输入流的状态被改变了,这是一个有意的副作用。

但也许你指的不是计算机科学意义上的副作用,而是某种特殊意义上的副作用。

你的第二个问题:"例如,对于这样的语句:,0, c += 2总是先求值,而第二个表达式c-= 1中的c总是从表达式c += 2中更新值,这是真的吗?"

对于语句或表达式,答案是肯定的,除非逗号操作符被重载(非常不寻常)。但是,像CC_11这样的序列也可以出现在参数列表中,在这种情况下,您得到的不是表达式,逗号不是序列操作符,并且没有定义求值的顺序。在CC_12中,逗号不是逗号操作符,但在CC_13中是,因此可能需要注意函数调用中的括号。