if(a && b)
{
do something;
}
是否有可能从右到左(b -> a)评估参数?
如果"是",那么会影响评估顺序的因素是什么?
(我正在使用VS2008)
if(a && b)
{
do something;
}
是否有可能从右到左(b -> a)评估参数?
如果"是",那么会影响评估顺序的因素是什么?
(我正在使用VS2008)
C++中只有几个运算符可以保证评估顺序
operator &&
先评估左操作数,如果逻辑值为 false
则避免评估右操作数。典型用法是例如 if (x > 0 && k/x < limit) ...
避免除以零的问题。
operator ||
先评估左操作数,如果逻辑值为 true
则避免评估右操作数。例如 if (overwrite_files || confirm("File existing, overwrite?")) ...
当标志位 overwrite_files
被设置时不会询问确认。
operator ,
先评估左操作数,然后无论如何都评估右操作数,并返回右操作数的值。这个运算符并不经常使用。请注意,在函数调用的参数之间的逗号不是逗号运算符,评估顺序也不能保证。
三元运算符x?y:z
先评估x
,然后根据结果的逻辑值仅评估y
或仅评估z
。
对于所有其他运算符,评估顺序未指定。
实际上,情况更糟,因为不仅没有规定顺序,而且表达式本身甚至没有“顺序”,例如在
std::cout << f() << g() << x(k(), h());
可能会按照 h-g-k-x-f
的顺序调用函数(这有点令人不安,因为 << 运算符的心理模型在某种程度上传达了顺序性的概念,但实际上只尊重结果放在流中的顺序而不是计算结果的顺序)。
显然,在表达式中的值依赖关系可能会引入一些顺序保证;例如,在上述表达式中,保证在调用 x(...)
之前将调用 k()
和 h()
,因为需要两者的返回值来调用 x
(C++ 不是lazy)。
还要注意,对于预定义运算符,&&
、||
和 ,
的保证仅在有效。如果您为自己的类型重载这些运算符,则它们在该情况下将像普通函数调用一样,并且操作数的求值顺序将是未指定的。
C++17 引入了一些额外的特定保证,关于求值顺序(例如在左移运算符 <<
中)。有关所有详细信息,请参见 https://dev59.com/yVkT5IYBdhLWcg3wf_pN#38501596。
(a + b) * c
这样的表达式中,必须在执行加法之前计算a
和b
,并且必须在乘法之前执行加法。通常,这种影响是不可观察的,但如果运算符被重载,它可能是可见的。 - James Kanzeif(b && a)
{
//do something
}
如果两个参数都是方法,并且您希望无论它们的结果如何都对它们进行评估:
bool rb = b();
bool ra = a();
if ( ra && rb )
{
//do something
}
a
之前先求值表达式b
。然而,要发生这种情况,运算符必须不是预定义的&&
逻辑与运算符,而是用户定义类型的重载运算符。在这种情况下,参数的求值顺序是未指定的(更糟糕的是,你甚至不能期望有实际的顺序,因为求值甚至可以被“交错”:一点点a
,然后一些b
,然后更多的a
,然后再一些b
的剩余部分,最后才调用自定义运算符)。 - 6502||
,情况会怎样?除非编译器进行了一些优化使其混乱,否则它应该保持不变,对吧 @6502? - mdw7326||
运算符时,表达式按顺序(从左到右)进行评估,直到所有表达式都被评估为真或找到一个为真的表达式,对吗? - mdw7326&&
和||
短路常见用法的示例。 - 6502&&
,a
将始终首先被评估,因为结果用于确定是否短路表达式。a
返回false,则不允许评估b
。operator&&
,否则不可能实现。虽然这是可能的,但被认为是不良设计。 - dalleObj * obj; if(obj && obj->foo()) {...}
我认为它检查obj是否不为NULL,并且仅在obj不为NULL时才会检查obj->foo()
的结果,对吗? - ruhig brauner&&
运算符总是先评估其左操作数。例如:if (a && b)
{
//block of code
}
a
为false
,那么b
将不会被评估。b
,只有在b
为真时才评估a
,那么只需要反过来写表达式即可:if (b && a)
{
//block of code
}
它将从左到右进行评估,并在可能的情况下短路评估(例如,如果a评估为false,则不会评估b)。
如果您关心它们被评估的顺序,您只需要在if语句中按所需的评估顺序指定它们即可。
if( b && a )
会为你完成。 - Prince John Wesley