可以将“运行时”分配器信息与C++中的分配器捆绑在一起吗?

huangapple go评论65阅读模式
英文:

Is it possible to bundle "runtime" allocator information with an allocator in C++?

问题

当我们为C++中的std::vector提供分配器时,请注意我们提供的是一个类分配器。类无法在运行时创建。

但是,如果我需要我的分配器依赖于运行时信息呢?例如,我们可能需要确定如何从特定用户输入分配内存。或者,如果我们想通过使用来自mmap文件的虚拟内存来创建向量,但在编译时不知道文件的情况下,那么我们也需要这个。当然,我们可以使用全局变量来实现这一点,但这显然不是一个好方法。

是否有可能在使用std::vector时存储这种运行时信息呢?

这个问题非常简单。然而,经过查找,我发现没有任何答案。显然,没有优雅的方法来实现这一点。

英文:

When we supply an allocator for std::vector in C++, note that we supply an allocator class. A class cannot be created at runtime.

However, what if I need my allocator to depends on runtime information? For example, we might need to determine how to allocate from the particular user input. Or, if we want to create a vector by using virtual memory from mmaping a file, but the file is not known at compile time, then we also need this. Surely we can use global variables for this, but surely that's not a good way.

Is it possible to store such runtime information in the use of std::vector?

The question is simple enough. However, after looking around, I see no answers at all. Apparently there are no elegant ways to do this?

答案1

得分: 1

这听起来你正在寻找 std::pmr::polymorphic_allocator,它是一个从 std::pmr::memory_resource 构造的分配器(实际上是一个分配器)。这允许你在运行时有效地选择分配器。

英文:

It sounds like you're looking for std::pmr::polymorphic_allocator, which is an allocator that is constructed from a std::pmr::memory_resource (which is effectively an allocator). This lets you effectively choose the allocator at runtime.

答案2

得分: 1

是的,这是可能的。标准库中的所有容器都满足 allocator-aware 要求。简单来说,这意味着容器必须将分配器存储为一个子对象,并在容器被复制、移动等操作时正确处理该对象。有两种实现有状态分配器的方法:

有状态的静态分配器

template <typename T>
struct mmap_allocator { /* ... */ };

mmap_allocator<data> create_mmap_allocator(std::string_view file) { /* ... */ }

auto create_vec() {
    std::vector<data, mmap_allocator<data>> result(create_mmap_allocator());
    /* ... */
    return result;
}

mmap_allocator 可以存储状态,比如已打开的文件是哪个,映射内存的指针等。一个明显的缺点是,这个 std::vector 现在与普通的 std::vector 不同,因为它使用了自定义的分配器。

多态分配器

如果你想要更多的自定义,比如在同一类型的向量中使用完全不同类型的分配器,这会变得繁琐。std::vector<T>std::vector<T, mmap_allocator<T>> 不兼容也很烦人。为了解决这个问题,有多态分配器

struct mmap_resource : std::pmr::memory_resource { /* ... */ };

mmap_resource create_mmap_resource(std::string_view file) {
    /* ... */
}

auto use_vec() {
    // TODO: 分配器不拥有内存资源,所以
    //       我们可能需要将向量和资源捆绑在一起
    //       在一个结构中等等。
    auto resource = create_mmap_resource(...);
    std::pmr::polymorphic_allocator alloc = &resource;
 
    std::pmr::vector<data> result(alloc);
    /* ... */
}

多态分配器是 std::pmr::memory_resource 的多态类包装器,你可以进行自定义。

还可以参考:polymorphic_allocator: when and why should I use it?

英文:

Yes, it's possible. All containers in the standard library satisfy the allocator-aware requirement. In simple terms, this means that the container has to store an allocator as a subobject, and handle this object correctly when the container is copied, moved, etc. There are two approaches to implementing stateful allocators:

Stateful Static Allocators

template &lt;typename T&gt;
struct mmap_allocator { /* ... */ };

mmap_allocator&lt;data&gt; create_mmap_allocator(std::string_view file) { /* ... */ }

auto create_vec() {
    std::vector&lt;data, mmap_allocator&lt;data&gt;&gt; result(create_mmap_allocator());
    /* ... */
    return result;
}

mmap_allocator can store state, such as which file was opened, a pointer to the mapped memory, etc. An obvious downside is that this std::vector is now distinct from a regular std::vector, since it uses a custom allocator.

Polymorphic Allocators

If you want even more customization, such as using a totally different type of allocator in the same vector type, this becomes annoying.
It's also annoying that std::vector&lt;T&gt; and std::vector&lt;T, mmap_allocator&lt;T&gt;&gt; are incompatible.
To solve this, there are polymorphic allocators:

struct mmap_resource : std::pmr::memory_resource { /* ... */ };

mmap_resource create_mmap_resource(std::string_view file) {
    /* ... */
}

auto use_vec() {
    // TODO: the allocator doesn&#39;t own the memory resource, so
    //       we might need to bundle the vector and the resource in
    //       a struct, etc.
    auto resource = create_mmap_resource(...);
    std::pmr::polymorphic_allocator alloc = &amp;resource;
 
    std::pmr::vector&lt;data&gt; result(alloc);
    /* ... */
}

Polymorphic allocators are wrappers for a polymorphic class std::pmr::memory_resource, which you can customize.

Also see: polymorphic_allocator: when and why should I use it?

huangapple
  • 本文由 发表于 2023年6月15日 00:53:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76475896.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定