在C++中,`x-- > 0 && array[x]`是否属于良好定义的行为?

11

当我在布尔表达式的左侧后置增量时,可以同时在两侧使用x吗?

问题所在的行是:

 if(x-- > 0 && array[x]) { /* … use x … */ }

这是否是通过标准定义的?array[x]会使用新值还是旧值?


7
记得保持你的代码整洁易读,即使它已经写得非常明确,如果有人稍后更改或添加表达式,它仍可能引入问题。这只是我的个人意见。 - AndersK
6
即使它可能被定义得很好,你也不应该使用这种代码。你可能在编写时理解它,但下一个人可能就无法理解。 - codymanix
这段代码其实还不错。我在 Linux 内核中见过更糟糕的代码 :D - knittl
请指定“x”的类型。如果“x”是整数,则是。如果它是一个类,取决于是否有人足够愚蠢地为该类定义了“&&”运算符(违反了所有已知的编码约定)。 - Martin York
@knittl “其实还不错”——这是很差的赞美。我不会用Linux内核来评判我的代码。我们不想写“还不错”的代码,我们想要写简单明了、清晰干净的代码。 - Rob K
2个回答

12

这要看情况而定。

如果&&是通常的短路逻辑运算符,那么没问题,因为有一个顺序点。此时array[x]将使用新值。

如果&&是用户(或库)定义的重载运算符,则没有短路,并且在评估x--和评估array[x]之间没有顺序点的保证。鉴于您提供的代码,这看起来不太可能发生,但是没有上下文很难确定。我认为,通过仔细定义array,可以安排成这样。

这就是为什么几乎总是不建议重载operator&&的原因。

顺便说一下,if ((x > 0) && array[--x])具有非常类似的效果(再次假设没有运算符重载诡计),并且在我看来更加清晰明了。区别在于是否会将x递减到0以下,取决于你是否依赖它。


它是布尔运算符&&,并且它没有重载。 - knittl
@Steve:即使&&被重载,它仍然是定义良好的行为,不是吗? - Armen Tsirunyan
@Zack:自从C++标准定稿以来,当然可以这样做,但在此之前我不确定。 - Steve Jessop
@Armen:我认为不行,尽管在这种情况下我并不完全确定。我的想法是假设x是整数类型,而array是某种类型T的数组,其中存在一个bool operator&&(bool,const T&)重载。那么在x--array[x]的评估之间没有序列点(因为它们都没有被重载),因此会导致未定义的行为。虽然我可能错过了一些使其定义的东西,但我是C++用户而不是C++编译器编写者,所以如果我要犯错,我会尝试从假定某些东西是未定义的方面出发。 - Steve Jessop
@Armen:如果x是int类型且array是数组类型,则无法对它们进行重载。 - Armen Tsirunyan
显示剩余2条评论

11

是的,这是定义良好的。 && 介绍了一个序列点。


1
哎呀,我有一种感觉,你或其他人正在使用像 Twitter 这样的反馈机制来回答问题,所以回答得这么快。当我第一次看到一个问题时,通常它已经被回答了...? - Cheers and hth. - Alf
1
那么,array[x]使用旧值还是新值? - knittl
@VJovic 内置的 && 运算符是短路的。这意味着只有在第一部分成功后,才会评估表达式的第二部分。这就是为什么 "if (X != NULL && X->foo == 2)" 是有效的原因。 - Kaz Dragon
@KazDragon 我想说的是我不知道&&引入了一个序列点。无论如何,我觉得那段代码相当糟糕。使用两个if语句更清晰、更容易调试。调试比起一开始编写代码来说要困难两倍。因此,如果你尽可能聪明地编写代码,那么根据定义,你并不足够聪明来进行调试。这一点尤其适用于其他人需要调试你的代码的情况,因为并非所有人都具有相同的知识和经验水平。 - BЈовић
@VJovic 在这里向信徒宣讲。我认为我所写的实际上非常通俗易懂:测试左侧,使用右侧的结果是一种非常常见的模式。然而,在此过程中修改左侧则需要仔细检查,符合你的抱怨。 - Kaz Dragon
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接