std::pmr::vector 分配失败未报错是因为自定义资源(如monotonic_buffer_resource)分配失败时返回空指针,而容器不检查,导致后续解引用崩溃;必须显式传入资源并确保其生命周期长于容器。

std::pmr::vector 为什么分配失败却没报错?
因为 std::pmr::vector 默认使用 std::pmr::new_delete_resource(),它底层调用 operator new,失败时抛 std::bad_alloc;但如果你传入自定义资源(比如 std::pmr::monotonic_buffer_resource),而缓冲区已满,allocate() 会直接返回空指针,STL 容器内部不检查该指针——导致后续解引用崩溃,而非抛异常。
- 务必在构造容器时显式传入资源,例如:
std::pmr::vector<int>{&my_pool}</int>,否则用的是全局默认资源 -
monotonic_buffer_resource不支持deallocate(),所有内存只能随资源对象销毁时一并释放,别指望手动回收 - 调试时加一层包装:重载
allocate(),在返回前断言ptr != nullptr,避免静默失败
std::pmr::polymorphic_allocator 的模板参数 T 真的必须和容器元素类型一致吗?
必须一致。虽然 std::pmr::polymorphic_allocator 是泛型模板,但它的 construct() 和 destroy() 依赖 T 的完整类型信息来调用正确构造/析构函数。若传入 polymorphic_allocator<char></char> 给 vector<string></string>,编译可能通过(因部分实现延迟实例化),但运行时 construct() 会尝试在 char* 上调用 string 构造函数,结果是未定义行为。
- 容器的
Allocator模板参数应始终与元素类型匹配:std::pmr::vector<:string std::pmr::polymorphic_allocator>></:string> - 别图省事写
using Alloc = std::pmr::polymorphic_allocator<void></void>——void版本是 C++20 废弃的,且无法用于构造对象 - 如果想复用同一块内存池管理多种类型,用同一个
std::pmr::memory_resource*构造不同类型的polymorphic_allocator即可,不用共用一个 allocator 实例
std::pmr::synchronized_pool_resource 在多线程下为何反而更慢?
因为它的内部锁粒度是「整个资源池」,不是按大小类或内存块分片。当多个线程高频申请小对象(如 int 或短 string),所有线程争抢同一把互斥锁,形成严重瓶颈。实测中,它常比单线程下还慢 3–5 倍。
- 高并发场景优先选
std::pmr::unsynchronized_pool_resource,再用外部线程局部存储(TLS)隔离 allocator 实例,例如每个线程持有一个polymorphic_allocator<int></int> -
synchronized_pool_resource仅适合低频、偶发、且需要跨线程共享内存池的场景(如日志缓冲区归集) - 注意:池资源初始化时的
options(如largest_required_pool_block)会影响内存碎片率,设得太小会导致频繁 fallback 到上游 resource,失去池的意义
std::pmr::memory_resource* 能安全跨 DLL 边界传递吗?
不能,除非你完全控制两边的 STL 实现和 ABI。Windows 下 MSVC 的 std::pmr::new_delete_resource() 返回的是 DLL 内部静态对象地址,若 A.dll 创建资源、B.exe 调用其 allocate(),而 B.exe 链接的是另一份 STL 实例,deallocate() 可能调到错误的 operator delete,引发堆损坏。
立即学习“C++免费学习笔记(深入)”;
- 跨模块时,只传递原始指针 + size,由接收方用自己的资源回收;或统一用系统 malloc/free 封装一层
memory_resource - Linux 下若用 libc++ 且全静态链接,风险略低,但仍不推荐——标准未保证
memory_resource的 ABI 稳定性 - 最稳妥的做法:模块间约定使用
std::pmr::null_memory_resource()作为占位符,实际内存管理交由上层协调
复杂点在于资源生命周期和容器生命周期的耦合——std::pmr::vector 不拥有 memory_resource*,你得确保资源对象活得比所有使用它的容器更久,否则就是悬垂指针。这点很容易被忽略,尤其在工厂函数或 lambda 捕获里临时创建资源时。









