我最近遇到了一个看起来像这样的代码段:
bool MyClass::do_work()
{
bool success = true;
for (auto const& worker : m_workers)
{
success &= worker.do_work(); // worker.do_work() returns a bool
}
return success;
}
如果我正确理解,如果所有工作程序返回true
,则函数返回true
,如果任何工作程序返回false,则函数返回false
。但是,它总是评估所有工作人员(这是期望的)。由于使用了按位运算符&=
而不是逻辑运算符&&
,因此不涉及短路评估。
这种行为是否得到保证?确切地说,是否保证按位&
总是计算两个操作数,即使它们是bool
类型也是如此?我遇到了许多关于&&
的保证短路评估的SO答案,但是没有一个答案表明存在&
的保证非短路评估。
如果可以保证这种行为,这是一种好的编程风格吗?我不仅仅快速浏览了一下该功能,因为我以前从未见过这种样式,起初我很困惑是否涉及短路评估。
是否有比以下更好的选择?
bool MyClass::do_work()
{
bool success = true;
for (auto const& worker : m_workers)
{
if (!worker.do_work())
{
success = false;
}
}
return success;
}
答案 0 :(得分:3)
除非标准明确指定,否则运算符的所有操作数都将在C ++中求值且未排序 1 :
除非另有说明,否则对单个运算符的操作数和单个表达式的子表达式的求值是无序列的。 [...] 运算符的操作数的值计算在运算符结果的值计算之前进行排序。 [...]
我想到的唯一三个例外是&&
,||
和?:
运算符 2 。
该标准甚至提到&&
3 :
与
&
不同,&&
保证从左到右求值:如果第一个操作数为false
,则不对第二个操作数求值。
至于这是一种好的编程风格,还是基于意见。
1 未排序基本上意味着,如果您拥有A @ B
(其中@
是运算符),B
(及其副作用)可以在A
之前被评估,这就是诸如i++ + ++i
are undefined behavior之类的构造的原因。
2 请注意,对于重载的&&
和||
运算符,这不再是正确的,因为两个操作数均被求值。 ?:
不能重载。
3 [expr.log.or]中的|
也有类似的注释。