【问题标题】:c++ bool concatenation with |=c++ bool 与 |= 的连接
【发布时间】:2017-02-06 10:22:36
【问题描述】:

我想知道连接布尔值的方法。

我有时需要得到一个标志,对象列表中的至少一个对象是否具有特定的值/状态/被聚焦等。

我要做的是:

bool bHasState( false );
for ( auto o : MyObjectList )
{
   bHasState |= ( o->state() == SOME_STATE );
}

我的一些同事总是将其替换为

bHasState = bHasState || ( o->state() == SOME_STATE );

这只是句法上的差异,还是我的方式错误、危险或缓慢?

【问题讨论】:

  • 我会使用if ( o->state() == SOME_STATE ) bHasState = true;,但无论哪种方式都可以。
  • Bo 的例子肯定更易读,更容易维护。
  • 是的,但是当我有时会编写实时关键代码时,我会问自己,在循环中使用 if 语句是否会更慢。
  • 如果时间紧迫,我怀疑for ( auto o : MyObjectList ) 你想到处复制。
  • 您的方式不使用短路运算符,因此,如果o->state() 必须执行复杂的计算(我对此表示怀疑)或获取一些互斥锁(肯定更有可能)|| 版本可能会有更好的性能(IOW,您必须平衡分支的成本与实际计算 state() 的成本)。 ||if 版本将基本相同(都有一个分支)。

标签: c++ boolean


【解决方案1】:

从 cmets 扩展:这里的主要区别是您的版本始终评估右手表达式,而带有 || 的版本(或建议的 if 版本,基本相同)不会,因为|| 有短路评估。1

性能差异归结为平衡分支的成本(一个很容易预测的成本,因为它总是会被占用,直到你找到一个使bHasState true 的元素,然后总是不被占用)与在每个项目上调用 state() 的成本,这可能非常便宜(如果它是直接内联访问器,那么唯一的成本将是潜在的缓存未命中)或相当昂贵(如果 state() 不是内联的,则执行更复杂的计算或者 - 比如说 - 必须获得一个繁忙的互斥体)。2

不过,如果您决定每次迭代的分支成本不会那么高,那么您可能应该更进一步:当您找到状态与您的状态匹配的第一个项目时,只需跳出循环寻找

bool bHasState( false );
for ( auto o : MyObjectList ) {
    if(o->state() == SOME_STATE) {
        bHasState = true;
        break;
    }
}

|| 分支确实很容易预测,但完全不循环不相关的项目肯定会更快,尤其是 MyObjectList 包含许多元素。


顺便说一句,同样的语义可以用这个可怕的标准库单行来重现:

bool bHasState = std::any_of(MyObjectList.begin(), MyObjectList.end(),
    [](MyObject const& o) { return o->state() == SOME_STATE; });

  1. IOW,仅当左侧表达式为false 时才计算右侧表达式;有人指出,如果|| 过载,它就不再是短路了,不过,我认为情况并非如此——从上下文来看,我们似乎正在处理常规整数。

  2. 1234563相反,它更喜欢,因为有或没有分支在技术上是不可观察的(就 C++ 标准而言)。

【讨论】:

  • 除非 MyObject 是智能指针,否则 lambda 应该接受指针而不是引用。
  • @Quentin: MyObject 原意为MyObjectList::value_type
【解决方案2】:

替换不相当相同。请继续阅读:

bHasState |= ( o->state() == SOME_STATE ); 是一种惯用的方式,如果右侧是 true,则打开位,如果右侧是 false,则保持原样。但它确实需要评估o->state(),如果这很昂贵,|| 替代方案可能会更好。

也就是说,对我来说,你目前拥有它的方式非常清楚。 (我个人会更进一步,删除多余的括号,这会使表达式看起来比实际更复杂。)

但根据经验,我也不会摆弄可以工作的代码,因为您可能会引入非常微妙的错误。目前o->state()总是被评估,如果你将它更改为bHasState = bHasState || ( o->state() == SOME_STATE );bHasState 已经是true,并且|| 没有被重载。 (请注意,如果 || 过载,||不会短路。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-04
    • 2021-08-28
    • 2014-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-04
    • 2016-08-07
    相关资源
    最近更新 更多