std::vector<bool>不能当Bitmap用,因其是位压缩特化,operator[]返回临时对象导致取地址失败、迭代器解引用生命周期短、无data()接口、resize可能丢数据,且set/test需严格边界检查与位运算规范。

直接用 std::vector<bool></bool> 实现海量去重,大概率在上线后崩溃或静默出错——它不是位图容器,而是带陷阱的布尔代理包装器。
为什么 std::vector<bool></bool> 不能当 Bitmap 用
它底层是位压缩特化,operator[] 返回的是临时 std::vector<bool>::reference</bool>,不是 bool&;这意味着:
-
&bitmap[i]编译失败,无法取地址做原子操作或 SIMD 加载 - 迭代器解引用结果生命周期极短,开
-O2后可能读到垃圾值 - 没有
data()接口,你拿不到原始字节数组,memset、memcpy、_mm256_load_si256全部失效 - 某些 STL 实现中,
resize()触发隐式重新分配,导致已设位丢失
set() 和 test() 的边界校验必须显式写死
Bitmap 构造参数是「最大可接受输入值」,不是元素个数。比如 BitMap(100) 表示支持 0~99,调用 set(100) 就越界了。
- 构造时应分配
(max_val + 63) / 64个uint64_t,而非模糊的n / 64 -
set(size_t i)开头必须有if (i >= size_) return;,不能依赖调用方过滤负数或超大值 -
test(size_t i)必须双检:i 且位掩码命中,否则未初始化内存返回随机值 - 调试期建议用
std::vector<uint64_t>::at(i / 64)</uint64_t>替代[],触发std::out_of_range
位索引计算必须用位运算,别用除法和取模
热点路径里 i / 64 和 i % 64 会触发 x86 除法微码,比位运算慢一个数量级。
立即学习“C++免费学习笔记(深入)”;
- 字索引改用
i >> 6,位偏移改用i & 63(64 位)或i & 7(8 位) - 置位表达式必须带
ULL后缀:data[i >> 6] |= (1ULL ,否则左移超过 31 位未定义 - 内存需对齐到 32 或 64 字节(用
aligned_alloc或alignas(64)),否则 AVX2 指令如_mm256_testc_si256直接 SIGSEGV
负数、稀疏大值、字符串怎么喂到位图里
位图只认非负整数索引,原始数据几乎从不满足这个前提。
- 含负数?拆成两个位图:
pos_bitmap存 ≥0 数,neg_bitmap存-x的绝对值 - 值域已知偏移(如 UID ∈ [100000, 10999999])?插入前统一减去
100000,再喂给BitMap(10900000) - 64 位整数且稀疏?放弃全量位图,改用两级结构:高 12 位作桶号,低 20 位作桶内偏移,每个桶配
std::bitset - 字符串?先过
std::hash<:string>()</:string>转成size_t,再按上述规则归一化;但注意哈希冲突,严格去重要加 fallback 哈希表
最常被忽略的一点:位图本身不存数据,只存“存在性”。想导出所有去重后的值,必须扫描全部位空间——哪怕只设了 100 个 bit,也要遍历 size_ 次。真要高频遍历,得额外维护插入顺序列表,或者直接换 roaringbitmap 库。


















