bitset是编译期固定大小的位数组,适用于位标记、开关集合、布尔状态压缩等场景,如灯泡状态记录、布隆过滤器、图算法邻接标记;不可用于动态位数需求。

bitset 是什么,什么时候该用它
bitset 不是动态容器,而是一个编译期确定大小的固定位数组。它适合做「位标记」「开关集合」「布尔状态压缩」这类场景,比如记录 100 个灯泡的亮灭、实现简单布隆过滤器、加速图算法中的邻接标记。别拿它当 vector 的替代品——后者是代理迭代器封装,bitset 才是真正按位存储、支持整数转换和位运算的原生工具。
构造与初始化的常见写法和陷阱
构造时必须指定模板参数 N(位数),且 N 必须是编译期常量。不能写 bitset(n 是变量);也不能用运行时值直接初始化所有位——除非转成字符串或整数。
-
bitset b1;:所有位默认为 0 -
bitset b2(42);:用无符号长整型初始化,等价于二进制00101010 -
bitset b3("1010");:字符串从右往左填充(低位在右),实际存为00001010 -
bitset b4(string("1100"));:同上,但注意string构造要求字符只能是'0'或'1',否则抛std::invalid_argument
错误示例:
int n = 16; bitsetb; // ❌ 编译失败:n 非常量表达式
常用操作函数和位运算符的区别
bitset 重载了全部位运算符(&、|、^、、>>),行为和内置整数一致;但要注意:所有运算返回新 bitset,不修改原对象(除非用复合赋值如 |=)。同时提供成员函数做更精细控制:
-
b.set():全置 1;b.set(i):置第i位(从 0 开始,高位在左) -
b.reset():全置 0;b.reset(i):清第i位 -
b.flip():全部翻转;b.flip(i):翻转第i位 -
b.test(i):返回bool,检查第i位是否为 1(越界会抛std::out_of_range) -
b.count():返回 1 的个数(内部通常用 CPU 指令如popcnt实现,很快) -
b.to_ulong()/b.to_ullong():转为整数(若位数超范围则抛异常)
注意:b[i] 返回的是 bitset::reference,可读可写,但不能取地址或绑定到 bool& —— 这是代理类的典型限制。
立即学习“C++免费学习笔记(深入)”;
性能和跨平台兼容性要点
bitset 内部通常按 unsigned long 数组实现,对齐和存储密度由标准库决定。它的优势在于:编译器能将多次位操作合并为单条指令,count() 和 any()/none() 常被优化为内建函数。但要注意:
- 大小超过
sizeof(unsigned long) * CHAR_BIT * N时,内存布局不可移植(不过你本来也不该依赖这个) - 不同平台下
to_ulong()的最大安全位宽不同(例如 32 位系统可能只支持 ≤32 位),建议优先用to_string()或分段处理 - 不要对大
bitset做频繁拷贝——它不是轻量对象,构造/赋值有开销
真正容易被忽略的是:当你需要“动态位数”时,bitset 完全不适用。这时候得切到 vector + 手动位索引,或者用 boost::dynamic_bitset。









