直接使用 std::allocator 需手动配对 allocate/deallocate 和 construct/destroy,否则引发 UB;allocate 仅分配原始内存,须 construct 才创建对象;deallocate 前必须 destroy 所有对象且 n 必须匹配;自定义 allocator 需实现 rebind 和 operator==/!=;allocate 失败抛 bad_alloc,无 OOM 回调机制。

直接用 std::allocator 没问题,但必须手动配对调用 allocate/deallocate 和 construct/destroy,漏一步就 UB(未定义行为)。
std::allocator::allocate 申请的是原始内存,不是对象
很多人以为 alloc.allocate(5) 就等于 new int[5],其实不是:allocate 只返回一块未构造的裸内存,里面没有 int 对象,不能直接读写。
- 必须后续调用
alloc.construct(p + i, value)才能在该地址上真正“诞生”一个int对象 - 如果跳过
construct直接赋值(如*(p+0) = 42),对非 POD 类型(比如std::string)是未定义行为 -
allocate(0)可能返回非空指针(例如指向 1 字节 dummy 内存),但你不能对它做任何construct或解引用操作
std::allocator::deallocate 前必须先 destroy 所有对象
deallocate 的前提是:这块内存上所有对象都已通过 destroy 显式析构。否则,对象的析构函数没被调用,资源(如文件句柄、堆内存)会泄漏。
- 顺序必须是:先循环调用
alloc.destroy(p + i),再调用alloc.deallocate(p, n) -
deallocate的第二个参数n必须和当初allocate(n)的参数完全一致,哪怕你只用了前 3 个位置,也不能传3 - 传错
n或重复deallocate同一块内存,常见报错是double free or corruption或直接崩溃
自定义 allocator 要实现 rebind 才能用于标准容器
如果你写了一个模板类 MyAlloc 并想让它作为 std::vector 的第二参数,光有 allocate 不够——容器内部可能需要为节点类型(如 std::vector 的内部 _Node)分配内存,这就要求你的 allocator 支持“换类型”。
- 必须提供嵌套模板
template<typename u> struct rebind { using other = MyAlloc<u>; };</u></typename> - 否则编译失败,典型错误:
no type named 'other' in 'MyAlloc::rebind ' - 还要重载
==和!=运算符(C++17 起可省略),否则某些容器在比较 allocator 实例时出错
std::allocator 本身不处理 OOM,异常得自己兜底
std::allocator::allocate 在内存不足时直接抛 std::bad_alloc,不会尝试调用 new-handler 或重试。如果你的场景不能接受抛异常(比如嵌入式或实时系统),就不能直接用它。
- SGI STL 的二级配置器(
__default_alloc_template)会在allocate失败时触发OOM_Handler回调,给你机会清理/日志/降级 - 想替代默认行为,得自己封装一层,比如用
::operator new(std::nothrow)替代malloc,再检查返回值 - 注意:即使用了
nothrow版本,construct仍可能抛异常(比如std::string构造时分配失败),这点常被忽略
最易被忽略的一点:容器(如 std::vector)内部调用 allocator 时,construct 和 destroy 是隐式发生的;但你自己手写容器或做底层内存管理时,这四步缺一不可,且顺序、参数、生命周期必须严丝合缝——差一个分号,就是野指针或静默崩溃。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











