为什么std :: bitset< 8> 4字节大?

时间:2011-09-22 07:49:19

标签: c++ visual-studio-2010 stl

似乎对于std :: bitset< 1到32>,大小设置为4个字节。对于33到64的大小,它会直接跳到8个字节。不能有任何开销,因为std :: bitset< 32>是一个偶数4个字节。

我可以看到在处理位时对齐字节长度,但为什么bitset需要与字长对齐,特别是对于最有可能在内存预算紧张的情况下使用的容器?

这是在VS2010下。

7 个答案:

答案 0 :(得分:5)

最可能的解释是bitset使用了大量机器字来存储数组。

这可能是出于内存带宽的原因而做的:读取/写入在字边界对齐的字通常相对便宜。另一方面,在某些体系结构上,读取(尤其是写入!)任意对齐的字节可能会很昂贵。

由于我们讨论的是每bitset个字节的固定大小的惩罚,这听起来像是一个通用库的合理权衡。

答案 1 :(得分:1)

现代机器上的存储器系统除了提取所需位的一些传统功能外,不能从存储器中获取除了字之外的任何其他内容。因此,使位组与字对齐使得它们处理起来要快得多,因为您不需要屏蔽掉访问它时不需要的位。如果你没有掩饰,做像

这样的事情
bitset<4> foo = 0;
if (foo) {
    // ...
}

很可能会失败。除此之外,我记得前段时间读过有一种方法可以将几个位组合在一起,但我不记得了。我认为,当你在一个结构中有几个位集时,它们可以占用“共享”内存,这不适用于大多数位域用例。

答案 2 :(得分:1)

我假设通过获取32位值然后隔离相关位来完成对位集的索引,因为这在处理器指令方面是最快的(在x86上使用较小大小的值较慢)。为此所需的两个索引也可以非常快速地计算出来:

int wordIndex = (index & 0xfffffff8) >> 3;
int bitIndex = index & 0x7;

然后你可以做到这一点,这也很快:

int word = m_pStorage[wordIndex];
bool bit = ((word & (1 << bitIndex)) >> bitIndex) == 1;

此外,每个位集最多浪费3个字节并不是内存问题恕我直言。考虑到bitset已经是存储此类信息的最有效数据结构,因此您必须将浪费评估为总结构大小的百分比。

对于1025位,这种方法使用了132个字节而不是129个,用于2.3%的开销(并且随着bitset站点的增加而下降)。考虑到可能的性能优势,这听起来很合理。

答案 3 :(得分:1)

我在Aix和Linux实现中具有相同的功能。在Aix中,内部bitset存储是基于char的:

typedef unsigned char _Ty;
....
_Ty _A[_Nw + 1];

在Linux中,内部存储基于很长时间:

typedef unsigned long _WordT;
....
_WordT            _M_w[_Nw];

出于兼容性原因,我们使用基于字符的存储修改了Linux版本

检查你在bitset.h中使用的实现

答案 4 :(得分:1)

因为32位Intel兼容处理器不能单独访问字节(或者更好,它可以通过隐式应用一些位掩码和移位),但是时间只能访问32位字。

如果您声明

bitset<4> a,b,c;

即使库将其实现为char,abc将是32位对齐的,因此存在相同的浪费空间。但是,在让bitset代码执行自己的掩码之前,处理器将被强制预先掩码字节。

出于这个原因,MS使用int[1+(N-1)/32]作为位的容器。

答案 5 :(得分:1)

如果你的std :: bitset&lt; 8>是一个结构的成员,你可能有这个:

struct A
{
  std::bitset< 8 > mask;
  void * pointerToSomething;
}

如果bitset&lt; 8&gt;存储在一个字节中(并且结构打包在1字节边界上)然后在结构中跟随它的指针将是未对齐的,这将是一个坏事。唯一一个具有bitset&lt; 8&gt;的安全和有用的时间。存储在一个字节中的是如果它在一个打包结构中,后跟一些其他一个字节的字段,可以将它打包在一起。我想这是一个过于狭窄的用例,因为它值得提供一个库实现。

基本上,在八叉树中,单字节位集只有在打包结构中被另外一到三个单字节成员跟随时才有用。否则,无论如何都必须将其填充到四个字节(在32位机器上)以确保以下变量是字对齐的。

答案 6 :(得分:0)

可能是因为它默认使用int,如果溢出则切换到long long? (只是猜测......)

相关问题