如何让std::pmr::map的分配器为std::string元素分配内存?
问题解答
1. std::pmr::map的分配器能否用于容器元素的内存分配?
可以,但需要满足两个前提:
- 容器的分配器需被包装为
std::scoped_allocator_adaptor,该适配器负责将外层容器的分配器传递给需要内部内存分配的元素(比如字符串、嵌套容器)。 - 元素类型要支持接收并使用外部分配器(即
std::uses_allocator<T, Alloc>::value == true)。
默认情况下,std::pmr::map的分配器是std::pmr::polymorphic_allocator,但普通std::string不会自动继承这个分配器——因为std::string的默认分配器是std::allocator<char>,与pmr分配器类型不兼容,且std::uses_allocator<std::string, std::pmr::polymorphic_allocator<char>>为false。
2. 让std::string使用map的pmr分配器的可行方案
你提到不想用std::pmr::string,但需要明确:普通std::string的分配器类型是固定的std::allocator<char>,无法直接替换为pmr分配器。如果坚持在代码中写std::string作为键类型,有两种可行方式:
方式一:typedef别名替换(本质还是pmr::string)
在局部作用域中将std::stringtypedef为std::pmr::string,这样代码中写std::string时,实际使用的是pmr兼容的字符串类型,会自动继承容器的分配器:
#include <map> #include <string> #include <memory_resource> // 在当前作用域内替换std::string为pmr版本 namespace std { using string = pmr::string; } int main() { char buffer[1024]; std::pmr::monotonic_buffer_resource pool(buffer, sizeof(buffer)); // 此时map的键是pmr::string,会自动使用pool的内存资源 std::pmr::map<std::string, uint8_t> test(&pool); test.emplace("example_key", 42); }
方式二:使用scoped_allocator_adaptor配合自定义可分配字符串类型
如果不想替换全局std::string,可以自定义一个包装std::string的类型,让它支持接收pmr分配器,再配合scoped_allocator_adaptor:
#include <map> #include <string> #include <memory_resource> #include <scoped_allocator> #include <type_traits> // 自定义支持分配器的字符串包装类 struct AllocAwareString { std::string data; // 带分配器的构造函数:利用pmr分配器为std::string分配内存 template <class Alloc> AllocAwareString(const char* s, const Alloc& alloc) : data(s, std::allocator<char>(alloc.resource())) {} // 支持map的键比较逻辑 bool operator<(const AllocAwareString& other) const { return data < other.data; } }; // 告诉scoped_allocator_adaptor该类型可以接收外部分配器 namespace std { template <class Alloc> struct uses_allocator<AllocAwareString, Alloc> : std::true_type {}; } int main() { char buffer[2048]; std::pmr::monotonic_buffer_resource pool(buffer, sizeof(buffer)); // 用scoped_allocator_adaptor包装pmr分配器 using MapAlloc = std::scoped_allocator_adaptor< std::pmr::polymorphic_allocator<std::pair<const AllocAwareString, uint8_t>> >; using MyMap = std::map<AllocAwareString, uint8_t, std::less<AllocAwareString>, MapAlloc>; // 初始化map,传入关联到自定义内存池的分配器 MyMap test(std::less<AllocAwareString>{}, MapAlloc{&pool}); // 插入元素:AllocAwareString会自动使用pool的资源分配内存 test.emplace("custom_key", 99); }
关键注意事项
- 普通
std::string无法直接通过scoped_allocator_adaptor使用pmr分配器,因为其分配器类型与pmr分配器不兼容。std::pmr::string是官方提供的pmr兼容字符串类型,也是最简洁的解决方案。 scoped_allocator_adaptor的核心场景是嵌套容器(如std::map<std::string, std::vector<int>>),让内层容器自动继承外层容器的分配器。
内容的提问来源于stack exchange,提问作者Abhijit
相关产品推荐
相关产品推荐

