std::bitset 不适合亿级整数去重,因其大小需编译期确定,易致编译失败、栈溢出或内存分配失败;应改用堆上动态分配、分块管理的自定义 bitmap 类,核心接口只需 set、test 和内存复用机制。

为什么 std::bitset 不适合亿级整数去重?
因为它的大小必须在编译期确定,比如 std::bitset 会直接让编译器报错或生成超大可执行文件;即便能编译,运行时也大概率触发栈溢出或内存分配失败。真正处理海量数据(如 1~10 亿范围整数)时,必须用堆上动态分配的位图,且要分块管理、按需加载。
手写 Bitmap 类该支持哪些核心接口?
不是所有位操作都需要暴露——实际去重场景只关心三个动作:插入、查询、内存复用。关键设计点:
-
set(uint32_t x):把第x位设为 1,需检查x是否越界(比如最大支持UINT32_MAX,但你只申请了 1GB 内存,对应约 86 亿位 → 实际上限是8600000000) -
test(uint32_t x):返回true表示已存在,注意未初始化的内存可能含随机值,务必在构造时用memset或std::vector<uint8_t>(size, 0)</uint8_t>清零 - 不提供
reset()全量清空——改用 placement new 重建对象或std::fill填 0 更可控,避免反复malloc/free开销
如何把内存占用压到最低?
常见错误是直接开 new uint8_t[size] 然后手动算字节和位偏移,容易越界或错位。正确做法:
- 用
std::vector<uint8_t></uint8_t>替代裸指针,自动管理生命周期 - 位图总长度按「目标最大值 + 1」向上对齐到 8 的倍数,再除以 8 得字节数;例如去重范围是 [0, 999999999],则需
(1000000000 + 7) / 8 = 125000000字节 ≈ 119 MB - 避免用
std::vector<bool></bool>—— 它是特化模板,行为不符合直觉(不能取地址、迭代器非随机访问),且某些 STL 实现性能极差 - 若数据稀疏(比如只存百万个数但值域达十亿),考虑用
roaring bitmap库替代,但纯 C++ 零依赖场景下,紧凑uint8_t数组仍是首选
真实去重流程中容易漏掉的边界点
读取文件逐行解析整数时,最常踩的坑不是算法,而是输入处理:
- 忘记跳过空行或注释行,导致
std::stoi抛std::invalid_argument - 没检查整数是否为负——如果业务约定只处理非负数,
set(-1)会把高位当掩码,造成静默错误 - 位图索引未做
x 判断就调用 <code>set(),越界写入会破坏相邻变量或触发 ASAN 报告 - 多线程写入同一
Bitmap实例却没加锁——set()不是原子操作(先读字节、改位、再写回),必须用std::atomic<uint8_t></uint8_t>或外层互斥量
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











