std::bitset - 如何迭代“已设置”(或“未设置”)的位?

3

我在我的代码中使用了位集:

std::bitset<MAX_INSTRUMENTS_NUMBER_IN_SYSTEM> updatedInstruments;

通常我只需要迭代“设置”的(或者“未设置”的)值,以下是我的做法:

for (int instrumentId = 0; instrumentId < MAX_INSTRUMENTS_NUMBER_IN_SYSTEM; instrumentId++) {
    if (!updatedInstruments[instrumentId]) {
        continue;
    }
    // work
}

这个迭代可以通过优化来使其更易读,也可能更快吗?

1个回答

0

我认为你无法利用std::bitset中位集合的连续性来编写代码:接口没有提供任何帮助完成这项任务的内容,并且没有合法的方法来访问底层存储并直接使用它。

如果你可以更改容器,你可以找到几个更好的替代方案。例如这里有一个类似于位集的结构,提供了“枚举器”来获取活动位(它似乎主要用于像图像跨度一样的工作),而在我上面链接的副本中,还有几个针对此用例更专业的数据结构的其他建议。


以前我认为迭代器可能会带来一些性能优势,但事实证明,std::bitset没有迭代器。另外,在std::vector上执行的类似测试(应该以大致相同的方式打包位)使用g++和clang++的迭代器都会导致约2倍的减速。

1
迭代器如何提高性能? - Lightness Races in Orbit
我不是说这是保证的,但我可以看到一些小的优化。使用索引需要重新计算底层存储中的位置、位移和掩码,而迭代器可以缓存一个单词(可能进入寄存器)并只需在那里进行移位,直到需要下一个单词为止。我只是从我的脑海中提取了这个例子,但通常在处理容器时,如果索引比指针求和+解引用更复杂,最好使用迭代器,因为它们被优化用于遍历。 - Matteo Italia
这在一般情况下是有道理的,但对于一个序列容器,我不太确定。在这里添加(add)和增量(inc)真的会有明显的区别吗? - Lightness Races in Orbit
当我在真正的计算机上时,我会进行一些测试。另一方面,很明显,在这里真正的优化(保持底层数据结构)就是完全跳过所有零或全设字节(甚至字),并且在“混合”字节中能够进行移位(以达到每个跨度的“边界”)而无需进行所有笨拙的布尔转换。这需要一个容器,要么为类似跨度的接口提供一些支持,要么更多地暴露其内部。 - Matteo Italia
@LightnessRacesinOrbit: 我刚试图进行基准测试,但是...天哪,std::bitset甚至没有迭代器!所以我想我的观点完全无效了... - Matteo Italia

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