c++中bool数组与bitset,vector<bool>的使用与占用空间大小对比

因为最近项目中需要对一个很大的二维数组记录是否使用过一个数据,所以我就想到了操作系统中对内存块的索引的方式,采用位图可以在O(1)复制度内设置是否使用以及查找是否能够使用,但是c++中对于bool型的变量的存储是按照1个字节(8bit)存储的,造成了内存空间的浪费,由于数组可能会很大(500W+)所以我想到用bitset来实现,但是由于我的程序运行中对于这个数组大小是不确定的,需要动态去确定,所以又带来了很多问题。下面就这些问题与解决方法做一下总结:

一、bool数组

c++中规定每个bool型变量占一个字节,这样对于内存的利用率很不高,但是bool数组的使用非常简答,在这就不过多阐述,下面直接说bitset与vector<bool>的使用。

二、bitset

bitset是c++STL中的一个类,关于其具体的使用方法,每个函数的调用方法,具体介绍参见c++标准库文档,其中介绍的非常详细还有简单的例子,我就不做过多叙述,下面就我的一些问题做一些说明。

首先,我们来看下bitset占用的内容空间的大小

bitset<1> bs1;

bitset<8> bs8;

bitset<16> bs16;

bitset<24> bs24;

bitset<50> bs50;

bitset<70> bs70;

bitset<150> bs150;

bitset<220> bs220;

 

 

cout<<"size of bs1 is\t\t"<<sizeof(bs1)<<endl;

cout<<"size of bs8 is\t\t"<<sizeof(bs8)<<endl;

cout<<"size of bs16 is\t"<<sizeof(bs16)<<endl;

cout<<"size of bs24 is\t"<<sizeof(bs24)<<endl;

cout<<"size of bs50 is\t"<<sizeof(bs50)<<endl;

cout<<"size of bs70 is\t"<<sizeof(bs70)<<endl;

cout<<"size of bs150 is\t"<<sizeof(bs150)<<endl;

cout<<"size of bs220 is\t"<<sizeof(bs220)<<endl;

vc中输出为:

size of bs1 is         4

size of bs8 is         4

size of bs16 is        4

size of bs24 is        4

size of bs50 is        8

size of bs70 is        16

size of bs150 is       24

size of bs220 is       32

我们可以看到bitset占用的空间确实会比使用bool型的数据小很多,但是其中确还是有些不明白的地方,为什么当我们只有一位的时候占用的字节数为4字节,如果按照不能跨界的原则的话也应该是1个字节或者两个字节,于是我查阅下相关资料,在bitset中计算其大小的时候并不是简单地不能跨界的原则,其是有一个计算规则的在32位机器上Size = 4 * ((N + 31) / 32)在64位机器上Size = 8* ((N + 63) / 64)这样我们就不难得到结果了,4*((1+31)/32) = 4,这样其实充分提高了内存的读写效率,确实是很聪明的作法。

但是bitset在定义变量时必须确定变量的大小,虽然说bitset也是一个容器,但是它并不像vector等容器那样可以动态增加容量,且其容量不能动态确定,比如下面的代码:

int x = 3;

bitset<x> b1;//Error! vc会报出这样的错误:IntelliSense:expression must have a constant value

bitset<10> bs;//Right!

由此,我们可以得出bitset在使用时必须先进行大小的确定,并且bitset没有提供修改其大小和添加删除元素的接口,故不能进行修改。这就限制了我在这个程序中的使用,因此我换用了vector<bool>的方法。

三、vector<bool>

vector<bool>实际是一个伪容器,并不保存真正的bool,而是打包bool以节省空间。在一个典型的实现中,每个保存在“vector”中的“bool”占用一个单独的比特,而一个8比特的字节将容纳8个“bool”。在内部,vector<bool>使用了与位域(bitfield)等价的思想来表示它假装容纳的bool。这样确实节省了空间,我们来看一下测试:

vector<bool> bv1(1,false);

vector<bool> bv8(8,false);

vector<bool> bv16(16,false);

vector<bool> bv24(24,false);

vector<bool> bv50(50,false);

vector<bool> bv70(70,false);

vector<bool> bv150(150,false);

vector<bool> bv220(220,false);

cout<<"size of bv1 is\t\t"<<bv1.capacity()<<endl;

cout<<"size of bv8 is\t\t"<<bv8.capacity()<<endl;

cout<<"size of bv16 is\t"<<bv16.capacity()<<endl;

cout<<"size of bv24 is\t"<<bv24.capacity()<<endl;

cout<<"size of bv50 is\t"<<bv50.capacity()<<endl;

cout<<"size of bv70 is\t"<<bv70.capacity()<<endl;

cout<<"size of bv150 is\t"<<bv150.capacity()<<endl;

cout<<"size of bv220 is\t"<<bv220.capacity()<<endl;

下面是输出结果:

size of bv1 is          32

size of bv8 is          32

size of bv16 is         32

size of bv24 is         32

size of bv50 is         64

size of bv70 is         96

size of bv150 is        160

size of bv220 is        224

此处的大小单位为bit,我们可以看到其实这个大小跟bitset申请的大小是一样的,计算方式也是一样的。但是,我在使用下标的方式读取这个容器内的数据时却发生了错误:

         vector<bool>bv(10,false);

         vector<bool>::iteratorit = bv.begin();

         inti =1;

         for(i = 0 ;i <10 ;i++)

         {

                   cout<<"element\t"<<i<<"\tis \t"<<bv[i]<<endl;

                //   i++; 此处多了一个i++,所以才出现错误。其实输出内容与迭代器的一样。

         }

我改用迭代器:

         vector<bool>bv(10,false);

         vector<bool>::iteratorit = bv.begin();

         inti =1;

         while(it!= bv.end())

         {

                   cout<<"element\t"<<i<<"\tis \t"<<*it<<endl;

                  it++;

                   i++;

         }

输出结果为:

element 1        is    0

element 2        is    0

element 3        is    0

element 4        is    0

element 5        is    0

element 6        is    0

element 7        is    0

element 8        is    0

element 9        is    0

element 10       is    0

输出正常,因此我们如果使用vctor<bool>的话,应该不要使用下标的方式进行访问,应当使用迭代器或者vector提供的其他函数进行使用,以免出现上述意想不到的结果,我的程序就是因为开始用了下标进行访问,导致我调试一个bug调试了好几个小时。

在c++文档中对vector<bool>介绍是这样的(详情戳这里):

It behaves like the unspecialized versionof vector, with thefollowing changes:

The storage is not necessarily an arrayof bool values, but the library implementation may optimize storageso that each value is stored in a single bit.

Elements are not constructed usingthe allocator object,but their value is directly set on the proper bit in the internal storage.

Member function flip and a newsignature for member swap.

A special member type, reference, aclass that accesses individual bits in the container's internal storage with aninterface that emulates a bool reference. Conversely, membertype const_reference is a plain bool.

The pointer and iterator types used by thecontainer are not necessarily neither pointers nor conforming iterators,although they shall simulate most of their expected behavior.

但是在Effective STL中的条款18并不建议使用vector<bool>,这里我就不再细说,可以在网上搜到很多解释,但是我个人觉得只要了解了这个容器的缺陷,在使用过程中避免下,有时还是可以使用的,比如我现在的这个程序。





  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是 `std::vector<bool>` 可能的操作及对应的完整示例: ```cpp #include <iostream> #include <vector> #include <bitset> int main() { // 创建空向量 std::vector<bool> bool_vec; // 添加元素 bool_vec.push_back(true); bool_vec.push_back(false); bool_vec.push_back(true); // 访问元素 std::cout << "bool_vec[0] = " << bool_vec[0] << std::endl; std::cout << "bool_vec[1] = " << bool_vec[1] << std::endl; std::cout << "bool_vec[2] = " << bool_vec[2] << std::endl; // 修改元素 bool_vec[1] = true; // 获取元素个数 std::cout << "bool_vec size = " << bool_vec.size() << std::endl; // 清空向量 bool_vec.clear(); // 判断向量是否为空 if (bool_vec.empty()) { std::cout << "bool_vec is empty" << std::endl; } // 创建指定大小的向量 std::vector<bool> bool_vec2(10); // 获取向量容量 std::cout << "bool_vec2 capacity = " << bool_vec2.capacity() << std::endl; // 调整向量大小 bool_vec2.resize(20); // 获取向量容量 std::cout << "bool_vec2 capacity = " << bool_vec2.capacity() << std::endl; // 获取向量最大元素个数 std::cout << "bool_vec2 max size = " << bool_vec2.max_size() << std::endl; // 获取指向向量首元素的指针 bool* ptr = &bool_vec2[0]; // 按位访问向量元素 for (int i = 0; i < bool_vec2.size(); ++i) { std::cout << "bool_vec2[" << i << "] = " << ((ptr[i / 8] >> (i % 8)) & 1) << std::endl; } // 使用 std::bitset 访问向量元素 std::bitset<20> bs(bool_vec2.to_ulong()); std::cout << "bool_vec2 as bitset: " << bs << std::endl; return 0; } ``` 该示例,首先创建了一个空的 `std::vector<bool>` 类型变量 `bool_vec`,并使用 `push_back` 方法添加了三个元素。然后,演示了访问和修改元素、获取元素个数、清空向量、判断向量是否为空、创建指定大小的向量、获取向量容量、调整向量大小、获取向量最大元素个数、获取指向向量首元素的指针、按位访问向量元素以及使用 `std::bitset` 访问向量元素等操作及对应的完整示例。 需要注意的是,在使用指针访问 `std::vector<bool>` 的元素时,需要进行位运算操作。由于 `std::vector<bool>` 的元素只占用 1 位空间,因此每个元素的地址只能按位访问,不能直接进行读写操作。同时,使用 `std::bitset` 可以方便地将 `std::vector<bool>` 转换为二进制串进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值