std::bitset<N> 实现导致大小被偷听

Posted

技术标签:

【中文标题】std::bitset<N> 实现导致大小被偷听【英文标题】:std::bitset<N> implementation causes size overheard 【发布时间】:2020-12-31 04:18:30 【问题描述】:

现在看起来 std::bitset&lt;N&gt;unsigned longs 的数组,这意味着当 N 很小时会有一个(很重?)开销。 sizeof(std::bitset&lt;8&gt;)8 bytes

底层数组本身的类型不是template 参数有什么原因吗?为什么在更合适的时候实现不使用uint32_t/16_t/8_t?我在实现中没有看到任何限制这一点的东西?

我猜我错过了一个特定的原因,但不确定如何寻找它,或者根本没有原因?由于这是一个如此简单的container,我无法理解这里似乎如何避免C++ 的零开销原则。

GCC 实现:https://gcc.gnu.org/onlinedocs/gcc-4.6.2/libstdc++/api/a00775_source.html

我相信clang是相似的(用sizeof来确认)

【问题讨论】:

这太棒了。也许使用std::array 并手动执行操作? 对于 N std::bitset,大小会很重要的现实场景是什么?我经常做嵌入式工作,我无法想象这样的场景。似乎不值得库实施者花时间进行优化。 @tumble 好吧,天真地你可以去bitset&lt;7&gt; arr[1024] 或类似的东西,用这个实现将是灾难性的。 @miles 你会将它添加到基类并压缩存储,而不是我怀疑的派生类。由于尺寸差异,这将是 ABI 中断,但否则不会有巨大风险。当然,由于多种原因,您无法将其添加到 std bitset 本身。 @pya 我的意思是,如果你复制到 bitset 并返回小东西,你应该很好;与机器字级操作相比,字节级位操作通常很糟糕。除非存储,这对我来说似乎不是问题。对于小型集合,您可以转换为/从 bitset。 【参考方案1】:

我无法理解这里似乎如何避免 C++ 的零开销原则。

零开销原则是一个原则,而不是 C++ 的绝对规则。

许多人在编译时固定容量有用的情况下使用std::vector。这种类型可能只有两个指针而不是三个指针,因此要小 50%。许多人使用std::string 在不可变字符串也可以工作的情况下,如果不是更好的话;它将减小字符串的大小(忽略 SSO)及其复杂性。以此类推。

这些都代表相对于标准类型的低效率。没有标准库类型可以处理所有可能的使用场景。此类类型的目标是广泛有用,而不是完美。

没有什么能阻止某人使用具有用户提供的底层类型的完全相同的接口编写 bitset 样式类型。但标准没有这种类型。

确实,没有什么能阻止bitset实现根据给定的位数选择底层类型。您的实现没有这样做,但它可以这样做。

【讨论】:

有道理,我不确定unsigned long 是事实是否有特殊原因。好像没有。谢谢!

以上是关于std::bitset<N> 实现导致大小被偷听的主要内容,如果未能解决你的问题,请参考以下文章

std::bitset<N>::count vs __builtin_popcount

为啥 std::bitset 不带有迭代器?

如何编写适用于 32 位和 64 位的 std::bitset 模板

如何将任何用户定义的类型转换为 std::bitset?

为啥 std::bitset<8> 变量无法处理 11111111?

为啥带有 unsigned long long 参数的 std::bitset 构造函数未标记为显式?