【问题标题】:What will be the result of this condition? Is it defined or compiler-dependant?这种情况会导致什么结果?它是定义的还是依赖于编译器的?
【发布时间】:2014-07-25 16:39:48
【问题描述】:

如果我想为变量分配一个新值并检查新值是否与旧值相同,我倾向于避免使用临时变量。我可以这样做吗:

if (oldval == (oldval = new_value()))
{
 ... do something
}

?
这种行为是明确定义的,还是评估优先级语言或编译器依赖?我可以试试这个看看结果,但它不能保证它也能在其他系统上工作。我是用 C++ 做的,所以这是我最感兴趣的语言,但如果行为与其他语言一致(或不一致),我想知道。

谢谢!

【问题讨论】:

  • 这样的代码永远不会得到舞会的日期。
  • @hacks 是的,我错了,在重新思考 10 秒后删除了我的评论 :)

标签: c++ conditional-statements operator-precedence


【解决方案1】:

== 的操作数的求值顺序没有定义(我假设== 没有重载)。不能保证oldval 将首先评估还是oldval = new_value() 将首先评估。在这种情况下,行为是未定义

避免编写访问变量值并在表达式的其他位置修改该变量的表达式


注意:只有运算符 ,&&||?: 保证操作数评估从左到右进行。所以,存在sequence point

  • &&(逻辑与)、||(逻辑或)(作为短路评估的一部分)和逗号运算符的左右操作数的计算之间。
  • 在三元“问号”运算符的第一个操作数与第二个或第三个操作数的求值之间。

【讨论】:

  • 嗯,我经常在条件表达式中使用它——利用这样一个事实,即当表达式的值已知时,评估停止。示例:if (x || y) ... - 如果 x 为真,则不评估 y。这对于这样的东西很有用:if (x == nullptr || !x->valid())
  • 我不认为是 UB 是 operator== 是用户定义的重载。
  • 只有像,&&||?:这样的运算符才能保证操作数的计算是从左到右进行的。
  • @juanchopanza;我没有考虑过重载的情况。编辑了答案。
  • 谢谢,这样更好,但在所有情况下都未指定评估顺序。如果运算符重载,则不是UB。这是 unspecifiedundefined 的事情。
【解决方案2】:

这将是未定义的行为,因为在 oldval = new_value() 中发生的对 oldval 的写入相对于使用 oldval 的值的值计算而言是无序的(ie== 左侧的求值)。

【讨论】:

  • 嗯,如果涉及的类型有一个重载的operator==,会不会有一个序列点?
  • @juanchopanza 是的,我想你是对的。在这种情况下,我们会得到operator==(oldval, oldval = new_value()),它看起来定义明确。
  • @juanchopanza 我不这么认为。虽然它保证oldvaloldval = new_value() 都将在operator== 开始之前完成评估,但似乎没有定义将两个参数评估为operator== 的顺序。 (但我正在阅读维基百科而不是标准。)
  • @MichaelUrman 如果operator== 通过引用获取其参数,则没有与传递第一个参数相关的值计算;任何值计算都将在operator== 的主体中进行,因此在修改后进行排序。我相信如果operator== 采用 value 的参数,那么它仍然是未定义的。 (但我不能 100% 确定参数的初始化是否是无序的 w.r.t. 参数评估。)
  • @MichaelUrman 如果两个操作数的求值是按顺序进行的,即使未指定求值的顺序,它也不是未定义的行为。
猜你喜欢
  • 2011-01-20
  • 1970-01-01
  • 1970-01-01
  • 2021-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-23
相关资源
最近更新 更多