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

C++ 为什么std::bitset<;8>;4字节大?,c++,visual-studio-2010,stl,C++,Visual Studio 2010,Stl,对于std::bitset,大小似乎设置为4字节。对于大小33到64,它直接跳到8字节。不会有任何开销,因为std::bitset是偶数4字节 在处理位时,我可以看到与字节长度对齐,但为什么位集需要与字长度对齐,特别是对于最有可能在内存预算紧张的情况下使用的容器 这是在VS2010下。可能是因为默认情况下它使用的是int,如果溢出,会切换到long?(只是猜测…最可能的解释是位集使用了大量机器字来存储数组 这可能是因为内存带宽的原因:读/写在字边界对齐的字通常相对便宜。另一方面,在某些体系结构中

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

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


这是在VS2010下。

可能是因为默认情况下它使用的是
int
,如果溢出,会切换到
long
?(只是猜测…

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

这可能是因为内存带宽的原因:读/写在字边界对齐的字通常相对便宜。另一方面,在某些体系结构中,读取(尤其是写入!)任意对齐的字节可能代价高昂


由于我们讨论的是固定大小的惩罚,即每个
位集有几个字节,这听起来像是一个通用库的合理折衷。

现代机器上的内存系统除了从内存中提取所需位的一些遗留函数外,无法从内存中提取字以外的任何东西。因此,将位集与字对齐可以大大加快处理速度,因为访问它时不需要屏蔽不需要的位。如果你不戴面具,做一些像

bitset<4> foo = 0;
if (foo) {
    // ...
}
位集foo=0;
如果(foo){
// ...
}

很可能会失败。除此之外,我记得不久前读过一篇文章,说有一种方法可以将多个比特集压缩在一起,但我记不太清楚了。我认为,当您在一个结构中有多个位集时,它们可以占用“共享”内存,这不适用于大多数位字段的使用情况。

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

int wordIndex = (index & 0xfffffff8) >> 3;
int bitIndex = index & 0x7;
然后你可以这样做,速度也很快:

int word = m_pStorage[wordIndex];
bool bit = ((word & (1 << bitIndex)) >> bitIndex) == 1;
int-word=mpstorage[wordIndex];
布尔位=((字和(1>比特索引)==1;

此外,每比特集的最大浪费3字节并不完全是内存问题。考虑到比特集已经是存储这种类型信息的最有效的数据结构,因此,您必须以总结构大小的百分比来评估浪费。


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

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

typedef unsigned char _Ty;
....
_Ty _A[_Nw + 1];
在Linux中,内部存储是基于长时间的:

typedef unsigned long _WordT;
....
_WordT            _M_w[_Nw];
出于兼容性原因,我们使用基于字符的存储修改了Linux版本


检查您在bitset.h内部使用的实现,因为32位Intel兼容处理器不能单独访问字节(或者更好,可以通过隐式应用一些位掩码和移位),但一次只能访问32位字

如果你申报

bitset<4> a,b,c;
位集a、b、c;
即使库将其实现为char,
a
b
c
也将是32位对齐的,因此同样存在浪费的空间。但处理器将被迫在让位集代码进行自己的掩码之前预掩码字节


因此,MS使用
int[1+(N-1)/32]
作为位的容器。

如果您的std::bitset<8>是结构的一个成员,您可能有以下情况:

struct A
{
  std::bitset< 8 > mask;
  void * pointerToSomething;
}
结构A { std::位集<8>掩码; void*指针方法; }
如果位集存储在一个字节中(并且结构压缩在1字节边界上)然后,在结构中跟随它的指针将不对齐,这将是一件坏事。将位集存储在一个字节中的唯一安全和有用的时间是,它位于压缩结构中,后跟其他一些可以将其压缩在一起的一个字节字段。我想这对于它来说是一个过于狭窄的用例o提供一个库实现是值得的


基本上,在八叉树中,一个单字节位集只有在压缩结构中后跟另一个一到三个单字节成员时才有用。否则,它必须填充到四个字节(在32位机器上)为了确保以下变量是字对齐的。

考虑到这是2011年,我不会将最大3个浪费字节称为内存问题。如果您只有其中一个字节,这不是内存问题。@Jon,JB-这就是问题所在,它不会只关注一个。但我在八叉树中使用位集作为掩码,这会使lo复合ST3字节数万次。@jalf:提问者是否已经耗尽内存有关系吗?即使没有,仍然值得知道你的代码可以扩展到多大程度,什么会阻止它,为什么。如果这个东西占用4字节,而它可以占用1字节,那么在任何情况下,它都是主要的部分对数据进行加密,就好像你的可用内存减少到了实际可用内存的1/4。使用1GB内存和4GB内存之间的区别不是很小,即使使用1.5MB和0.4MB之间的区别是。@jalf:hmm,我经常编写占用一两GB内存的程序,所以对我来说,这种开销是很明显的现在的危险是我必须意识到的,所以我知道什么时候应该避免它。对页面文件的重击并不能提高性能,即使word和byte access能够提高性能!这可能给了我一个扭曲的视角,不适用于编写比较起来只能被视为“玩具”的东西的程序员仅能容纳几百MB的应用程序;-pI