我想使用带有std::pmr::monotonic_buffer_resource
的std::pmr::unordered_map
。这两者很搭配,因为该集合的节点是稳定的,所以不需要通过重新分配来创建大量的缓冲区空洞:
std::pmr::monotonic_buffer_resource res;
std::pmr::unordered_set<T> set(&res);
那就是说,除了bucket list之外,在set重新散列时需要重新分配,因为它超过了max_load_factor()。假设我无法通过reserve()解决这个问题,并且我真的关心由旧bucket list留下的缓冲区资源中的空洞,那么我的选择是什么?
如果我知道unordered_set是作为std::vector实现的(在某些版本的MSVC中),那么我应该能够使用scoped_allocator为vector和forward_list提供不同的分配器。但是a)我不能在可移植代码中依赖于unordered_set是一个vector,并且b)scoped_allocator是一个分配器,而monotonic_buffer_resource是一个memory_resource,这种阻抗不匹配将导致非常复杂的初始化。
或者我可以编写一个switch_memory_resource,根据请求的大小委托给其他memory_resource。然后,我可以为与节点大小匹配的请求使用monotonic_buffer_resource(但是,我也无法在可移植方式中知道节点的大小),并为其他所有请求使用default_memory_resource()。我可能可以做出合理的猜测,即节点最多为sizeof(struct {void* next; size_t hash; T value;}),通过将其乘以2来添加误差边界,并将其用作两个memory_resource之间的切换点,但我想知道是否有更简洁的方法?
pmr::unordered_set<pmr::string>
的优点非常出色。这证明了任何根据请求大小切换的做法都会导致失败。我认为我希望有一种形式的作用域分配器支持,这样你就可以在顶层知道请求只是用于存储桶列表,在下一个请求中用于节点,在第三个及其后续请求中用于值类型。例如monotonic_buffer_resource mbr; scoped_memory_resource{default_memory_resource(), &mbr, &mbr};
,其中最后一个&mbr
是多余的,就像scoped_allocator_adapter
中一样。 - Marc Mutz - mmutzvector
模式将是其中之一的提示。 - Pablo Halpern