逗号操作员是否没有副作用?

时间:2011-10-16 14:05:30

标签: c++ expression

例如对于这样的陈述:

c += 2, c -= 1

是否真的始终首先评估c + = 2,并且第二个表达式c- = 1中的c将始终是表达式c + = 2的更新值?

5 个答案:

答案 0 :(得分:9)

是的,它由标准保证,只要该逗号是非重载的逗号运算符即可。引用n3290§5.18:

  

逗号运算符从左到右分组。

     
    

表达式:
     赋值表达式      表达式,赋值表达式

  
     

用逗号分隔的一对表达式从左到右进行评估;左表达式被丢弃 -   价值表达(第5条) 83 。与左表达式相关的每个值计算和副作用   每个值计算和与右表达式相关的副作用之前排序。类型   结果的值是右操作数的类型和值;结果具有相同的值类别   作为右操作数,如果右操作数是glvalue和位域,则为位字段。

以及相应的脚注:

  

83 但是,重载逗号运算符的调用是一个普通的函数调用;因此,对其论点的评价   表达式相对于彼此没有排序(见1.9)。

因此,对于非重载的逗号运算符,这只包含

函数参数之间的,不是逗号运算符。此规则也不适用于此。

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

  

逗号运算符从左到右分组。

     
    

表达式:
    赋值表达式     表达式,赋值表达式

  
     

用逗号分隔的一对表达式从左到右进行计算,左表达式的值为   丢弃。左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)标准收敛 -   sions不适用于左表达式。 左表达的所有副作用(1.9),除了   在评估正确的表达之前执行临时的破坏(12.2)。类型和   结果的值是右操作数的类型和值;如果右操作数为。

,则结果为左值

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

答案 1 :(得分:7)

是的,逗号运算符保证语句按从左到右的顺序进行计算,返回的值是最右边的计算语句。

但请注意,某些上下文中的逗号不是逗号运算符。例如,函数参数列表不保证以上内容。

答案 2 :(得分:4)

是的,在C ++中,逗号运算符是一个序列点,这些表达式将按照它们的写入顺序进行计算。请参阅当前工作草案中的5.18

  

[snip]从左到右进行评估。 [剪断]

我觉得你的问题缺乏对“副作用”的含义的一些解释。允许C ++中的每个语句都有副作用,因此重载的逗号运算符也是如此。

为什么您所写的声明在函数调用中无效?

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

答案 3 :(得分:1)

应始终从左到右进行评估,因为这是逗号运算符的定义: Link

答案 4 :(得分:0)

你有两个问题。

第一个问题:“逗号操作员是否没有副作用?”

答案是否定的。逗号运算符自然地有助于编写具有副作用的表达式,并且故意编写具有副作用的表达式是操作员通常使用的表达式。例如,在while (cin >> str, str != "exit")中输入流的状态发生了变化,这是一种有意的副作用。

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

你的第二个问题:“例如对于这样的陈述:c += 2, c -= 1 c + = 2总是首先被评估,而第二个表达式c- = 1中的c将始终是表达式c的更新值+ = 2?“

对于语句或表达式,答案是肯定的,除非逗号运算符过载(非常不寻常)。但是,c += 2, c -= 1之类的序列也可以出现在参数列表中,在这种情况下,您所获得的不是表达式,逗号不是序列运算符,并且未定义评估顺序。在foo(c += 2, c -= 1)中,逗号不是逗号运算符,但在foo((c += 2, c -= 1))中它是,所以在函数调用中注意括号可能会付出代价。