C++17引入的std::pmr(Polymorphic Memory Resources)是一套多态内存资源框架,核心目标是让内存分配策略可以在运行时动态切换,解决传统静态分配器无法适配多场景内存需求的问题。它把内存分配的逻辑和具体使用内存的业务代码解耦,开发者只需要替换底层的内存资源对象,就能改变整个模块的内存分配行为。

std::pmr的核心价值
传统的C++内存分配依赖全局的new/delete或者模板化的静态分配器,分配策略在编译期就固定了,想要切换不同的分配逻辑往往需要修改大量代码。而std::pmr通过多态的设计,让内存资源成为可以运行时替换的对象,主要有以下几个核心用途:
- 解耦内存分配逻辑和业务代码,业务代码不需要感知底层是用堆分配、内存池分配还是栈分配
- 支持运行时动态切换分配策略,同一个容器在不同场景下可以使用不同的内存资源
- 提供标准的内存资源实现,比如
std::pmr::new_delete_resource、std::pmr::null_memory_resource、std::pmr::unsynchronized_pool_resource等,开箱即用 - 方便实现自定义内存资源,适配特殊场景的内存分配需求,比如共享内存、预分配内存块等
std::pmr的核心组件
std::pmr的体系主要包含三个核心部分:
1. 内存资源基类std::pmr::memory_resource
这是一个抽象基类,定义了内存分配的核心接口,所有自定义内存资源都需要继承这个类并实现对应的虚函数:
#include <memory_resource>
// 自定义内存资源示例,继承std::pmr::memory_resource
class custom_memory_resource : public std::pmr::memory_resource {
private:
// 实现分配内存的虚函数
void* do_allocate(size_t bytes, size_t alignment) override {
// 这里可以实现自定义分配逻辑,比如从预分配的内存池中分配
return ::operator new(bytes);
}
// 实现释放内存的虚函数
void do_deallocate(void* p, size_t bytes, size_t alignment) override {
::operator new(p);
}
// 实现相等判断的虚函数,判断两个内存资源是否等价
bool do_is_equal(const memory_resource& other) const noexcept override {
// 通常判断类型是否相同即可
return typeid(other) == typeid(*this);
}
};
2. 标准内存资源实现
C++标准已经提供了几个常用的内存资源实现,开发者可以直接使用:
| 内存资源类型 | 作用说明 |
|---|---|
| std::pmr::new_delete_resource | 使用全局的new和delete进行内存分配,是默认的内存资源 |
| std::pmr::null_memory_resource | 分配内存时直接抛出异常,用于测试不允许内存分配的场景 |
| std::pmr::synchronized_pool_resource | 线程安全的内存池资源,适合多线程场景下的频繁小内存分配 |
| std::pmr::unsynchronized_pool_resource | 非线程安全的内存池资源,单线程场景下性能更高 |
3. 多态分配器std::pmr::polymorphic_allocator
这是一个分配器模板,作为容器和内存资源之间的桥梁,它内部持有一个std::pmr::memory_resource*指针,所有分配操作都委托给这个指针指向的内存资源。标准容器只要使用这个分配器,就能支持运行时切换内存资源。
运行时内存策略切换示例
下面通过一个完整的示例展示如何使用std::pmr实现运行时内存策略的切换:
#include <iostream>
#include <memory_resource>
#include <vector>
#include <string>
int main() {
// 1. 使用默认的内存资源(new_delete_resource)创建pmr容器
std::pmr::vector<int> vec1;
vec1.push_back(1);
vec1.push_back(2);
std::cout << "使用默认内存资源,vec1大小: " << vec1.size() << std::endl;
// 2. 准备一个内存池资源
std::pmr::unsynchronized_pool_resource pool_res;
// 3. 运行时切换到内存池资源,创建新的pmr容器
std::pmr::vector<int> vec2{&pool_res};
vec2.push_back(3);
vec2.push_back(4);
vec2.push_back(5);
std::cout << "使用内存池资源,vec2大小: " << vec2.size() << std::endl;
// 4. 自定义内存资源示例
class log_memory_resource : public std::pmr::memory_resource {
public:
void* do_allocate(size_t bytes, size_t alignment) override {
std::cout << "分配内存,大小: " << bytes << " 字节" << std::endl;
return ::operator new(bytes);
}
void do_deallocate(void* p, size_t bytes, size_t alignment) override {
std::cout << "释放内存,大小: " << bytes << " 字节" << std::endl;
::operator delete(p);
}
bool do_is_equal(const memory_resource& other) const noexcept override {
return typeid(other) == typeid(*this);
}
};
log_memory_resource log_res;
// 运行时切换到自定义日志内存资源
std::pmr::string str{&log_res};
str = "hello std::pmr";
std::cout << "自定义内存资源下的字符串: " << str << std::endl;
return 0;
}
上面的示例中,vec1使用默认的内存资源,vec2在构造时传入了内存池资源的指针,就切换到了内存池分配策略,str则使用了自定义的带日志功能的内存资源,整个过程不需要修改容器的使用逻辑,只需要在构造时传入不同的内存资源指针即可,完美实现了运行时内存策略的切换。
使用注意事项
- std::pmr是C++17引入的特性,使用时需要保证编译器支持C++17及以上标准
- 内存资源的生命周期需要长于使用它的容器,避免容器还在使用内存资源时资源已经被释放
- 多线程场景下如果使用非线程安全的内存资源,需要自己加锁保证线程安全,或者直接使用
std::pmr::synchronized_pool_resource - 自定义内存资源时,需要正确实现三个虚函数,尤其是do_is_equal函数,否则可能导致容器之间的分配器比较出现问题
std::pmr的核心优势在于把内存分配策略的决策从编译期推迟到运行时,让内存管理更加灵活,尤其适合需要适配多种内存分配场景的库开发或者性能敏感的程序优化。
std::pmrPolymorphic_Memory_Resources内存分配器运行时内存策略c++修改时间:2026-07-13 12:06:33