有没有办法为向量采用内存资源?
is there any way to adopt a memory resource for a vector?
我已经开始在我的项目中使用 pmr::allocators,我已经看到使用它们带来的性能提升和优势。我使用的分配器与我在下面的简单示例中展示的非常相似:
#include <array>
#include <boost/container/flat_map.hpp>
#include <cassert>
#include <iostream>
#include <memory_resource>
#include <string>
#include <vector>
struct MessageBody {
using map_t = boost::container::flat_map<
char, char, std::less<char>,
std::pmr::polymorphic_allocator<std::pair<char, char>>>;
using vector_t = std::vector<char, std::pmr::polymorphic_allocator<char>>;
MessageBody(std::pmr::memory_resource& mem_v,
std::pmr::memory_resource& mem_m)
: vec_(0, &mem_v), map_(&mem_m) {}
vector_t vec_;
map_t map_;
};
int main() {
std::array<char, 1000> buffer;
buffer.fill('[=10=]');
std::pmr::monotonic_buffer_resource vec_mem(buffer.data(), 500,
std::pmr::null_memory_resource());
std::pmr::monotonic_buffer_resource map_mem(buffer.data() + 500, 500,
std::pmr::null_memory_resource());
{
MessageBody message(vec_mem, map_mem);
message.vec_.push_back('1');
assert(message.vec_.size() == 1);
}
{
MessageBody message(vec_mem, map_mem);
assert(message.vec_.size() == 1); /// I want to adopt the previous class for a new class.
}
}
我的问题是是否有任何方法可以将 memory_resources
用于另一个 class 而无需在 vector
和 map
中重新填充整个数据。
我能想到的唯一方法(我知道这是一个糟糕的想法)是实现一个新的 class 继承自 std::vector,即 class有一个 adopt data 方法,在不修改缓冲区的情况下将向量内部的 size
设置为先前使用的向量的大小。
这里有一个 link 的例子。
您想要的不是采用内存资源 - 因为您可以而且可以做到 - 而是也将向量本身存储在那里。
你可以,例如使用助手创建带有自定义删除器的 unique_ptr:
template <typename T>
inline static auto make_T(Mem& mem) {
std::pmr::polymorphic_allocator<T> alloc(&mem);
return std::unique_ptr{
alloc.template new_object<T>(), // allocator is propagated
[alloc](T* p) { alloc.delete_object(p); }};
}
It requires a bit more work when the library support for C++20 is not complete, so let me show that in a live demo on Compiler Explorer
但是,您无法使用内存的 C++ 抽象机器模型在同一内存上“复活”非平凡类型。
缓冲区中的活动对象 - 输入 Boost Interprocess
您真正想要的是在那里存储/活动对象/并从其他地方访问它们。
您可以使用共享内存分配器来做到这一点,例如 Boost Interprocess。您可以在
- 手动分配缓冲区(如单调的内存资源)
- 托管共享内存段
- 托管映射文件
在后一种情况下当然有持久化和多进程访问的好处。
If you don't need IPC or persistence, but like the managed segment abilities, use managed_external_buffer
使用托管外部缓冲区的演示
设置几个类型定义:
namespace Shared {
using Mem = bip::managed_external_buffer;
template <typename T>
using Alloc = boost::container::scoped_allocator_adaptor<
bip::allocator<T, Mem::segment_manager>>;
template <typename T>
using Vector = boost::container::vector<T, Alloc<T> >;
template <typename K, typename V, typename Cmp = std::less<K>>
using Map =
boost::container::flat_map<K, V, std::less<K>, Alloc<std::pair<K, V>>>;
} // namespace Shared
请注意我是如何使用 scoped_allocator_adaptor 来尽可能接近 PMR 根据 uses_allocator<>
.
将容器分配器传播到元素类型的行为
struct MessageBody
{
using map_t = Shared::Map<char, char>;
using vector_t = Shared::Vector<char>;
template <typename Alloc>
MessageBody(Alloc alloc) : vec_(alloc), map_(alloc)
{ }
vector_t vec_;
map_t map_;
};
不再需要unique_ptr,你的数据结构基本上就是你的数据结构,但是我们将所有内容都存储在一个内存资源中,所以整个东西可以“复活”为一个:
int main() {
std::array<char, 1000> buffer;
buffer.fill('[=13=]');
{
Shared::Mem mem(bip::create_only, buffer.data(), buffer.size());
auto& message = *mem.find_or_construct<MessageBody>("message")(
mem.get_segment_manager());
message.vec_.push_back('1');
assert(message.vec_.size() == 1);
}
{
Shared::Mem mem(bip::open_only, buffer.data(), buffer.size());
auto& message = *mem.find_or_construct<MessageBody>("message")(
mem.get_segment_manager());
assert(message.vec_.size() == 1);
}
std::cout << "Bye" << "\n";
}
get_segment_manager()
调用 returns 一个指针作为 Shared::Alloc<>
个实例的初始值设定项。
现在它运行通过断言:Live On Coliru
只打印
Bye
我已经开始在我的项目中使用 pmr::allocators,我已经看到使用它们带来的性能提升和优势。我使用的分配器与我在下面的简单示例中展示的非常相似:
#include <array>
#include <boost/container/flat_map.hpp>
#include <cassert>
#include <iostream>
#include <memory_resource>
#include <string>
#include <vector>
struct MessageBody {
using map_t = boost::container::flat_map<
char, char, std::less<char>,
std::pmr::polymorphic_allocator<std::pair<char, char>>>;
using vector_t = std::vector<char, std::pmr::polymorphic_allocator<char>>;
MessageBody(std::pmr::memory_resource& mem_v,
std::pmr::memory_resource& mem_m)
: vec_(0, &mem_v), map_(&mem_m) {}
vector_t vec_;
map_t map_;
};
int main() {
std::array<char, 1000> buffer;
buffer.fill('[=10=]');
std::pmr::monotonic_buffer_resource vec_mem(buffer.data(), 500,
std::pmr::null_memory_resource());
std::pmr::monotonic_buffer_resource map_mem(buffer.data() + 500, 500,
std::pmr::null_memory_resource());
{
MessageBody message(vec_mem, map_mem);
message.vec_.push_back('1');
assert(message.vec_.size() == 1);
}
{
MessageBody message(vec_mem, map_mem);
assert(message.vec_.size() == 1); /// I want to adopt the previous class for a new class.
}
}
我的问题是是否有任何方法可以将 memory_resources
用于另一个 class 而无需在 vector
和 map
中重新填充整个数据。
我能想到的唯一方法(我知道这是一个糟糕的想法)是实现一个新的 class 继承自 std::vector,即 class有一个 adopt data 方法,在不修改缓冲区的情况下将向量内部的 size
设置为先前使用的向量的大小。
这里有一个 link 的例子。
您想要的不是采用内存资源 - 因为您可以而且可以做到 - 而是也将向量本身存储在那里。
你可以,例如使用助手创建带有自定义删除器的 unique_ptr:
template <typename T>
inline static auto make_T(Mem& mem) {
std::pmr::polymorphic_allocator<T> alloc(&mem);
return std::unique_ptr{
alloc.template new_object<T>(), // allocator is propagated
[alloc](T* p) { alloc.delete_object(p); }};
}
It requires a bit more work when the library support for C++20 is not complete, so let me show that in a live demo on Compiler Explorer
但是,您无法使用内存的 C++ 抽象机器模型在同一内存上“复活”非平凡类型。
缓冲区中的活动对象 - 输入 Boost Interprocess
您真正想要的是在那里存储/活动对象/并从其他地方访问它们。
您可以使用共享内存分配器来做到这一点,例如 Boost Interprocess。您可以在
- 手动分配缓冲区(如单调的内存资源)
- 托管共享内存段
- 托管映射文件
在后一种情况下当然有持久化和多进程访问的好处。
If you don't need IPC or persistence, but like the managed segment abilities, use
managed_external_buffer
使用托管外部缓冲区的演示
设置几个类型定义:
namespace Shared {
using Mem = bip::managed_external_buffer;
template <typename T>
using Alloc = boost::container::scoped_allocator_adaptor<
bip::allocator<T, Mem::segment_manager>>;
template <typename T>
using Vector = boost::container::vector<T, Alloc<T> >;
template <typename K, typename V, typename Cmp = std::less<K>>
using Map =
boost::container::flat_map<K, V, std::less<K>, Alloc<std::pair<K, V>>>;
} // namespace Shared
请注意我是如何使用 scoped_allocator_adaptor 来尽可能接近 PMR 根据 uses_allocator<>
.
struct MessageBody
{
using map_t = Shared::Map<char, char>;
using vector_t = Shared::Vector<char>;
template <typename Alloc>
MessageBody(Alloc alloc) : vec_(alloc), map_(alloc)
{ }
vector_t vec_;
map_t map_;
};
不再需要unique_ptr,你的数据结构基本上就是你的数据结构,但是我们将所有内容都存储在一个内存资源中,所以整个东西可以“复活”为一个:
int main() {
std::array<char, 1000> buffer;
buffer.fill('[=13=]');
{
Shared::Mem mem(bip::create_only, buffer.data(), buffer.size());
auto& message = *mem.find_or_construct<MessageBody>("message")(
mem.get_segment_manager());
message.vec_.push_back('1');
assert(message.vec_.size() == 1);
}
{
Shared::Mem mem(bip::open_only, buffer.data(), buffer.size());
auto& message = *mem.find_or_construct<MessageBody>("message")(
mem.get_segment_manager());
assert(message.vec_.size() == 1);
}
std::cout << "Bye" << "\n";
}
get_segment_manager()
调用 returns 一个指针作为 Shared::Alloc<>
个实例的初始值设定项。
现在它运行通过断言:Live On Coliru
只打印
Bye