Я новичок в boost и хочу знать, как именно библиотеки boost :: pool могут помочь мне в создании собственного распределителя памяти.
И у меня есть два вектора объектов структуры.
Первый вектор имеет структурный тип A, а второй вектор имеет структурный тип B.
Как можно повторно использовать память, выделенную первому вектору, второму вектору.
Boost Pool — это библиотека, которая определяет несколько типов распределителей.
Очевидно, что целью библиотеки является обеспечение пула распределителей.
Выделители пула светятся, когда вы выделяете объекты одинакового размера.
Заметка Если ваша структура
A
и структураB
не идентичны / очень похожего размера, вам может не понравиться это предположение о дизайне.
Распределители, предоставляемые платформой, работают с одноэлементными пулами, и они различаются по размеру вашего контейнера value_type. Это немного негибко, если вы хотите повторно использовать или даже разделять пул между различными типами значений. Кроме того, одноэлементные пулы могут быть негибкими и подразумевать затраты на безопасность потоков.
Итак, я хотел посмотреть, смогу ли я создать самый простой распределитель, который устраняет некоторые из этих проблем.
Я использовал источник для boost::pool_alloc
и пример cppreference в качестве вдохновения, а затем провел некоторое тестирование и профилирование памяти.
Вот простейший распределитель пула, о котором я мог подумать:
using Pool = boost::pool<boost::default_user_allocator_malloc_free>;
template <typename T> struct my_pool_alloc {
using value_type = T;
my_pool_alloc(Pool& pool) : _pool(pool) {
assert(pool_size() >= sizeof(T));
}
template <typename U>
my_pool_alloc(my_pool_alloc<U> const& other) : _pool(other._pool) {
assert(pool_size() >= sizeof(T));
}
T *allocate(const size_t n) {
T* ret = static_cast<T*>(_pool.ordered_malloc(n));
if (!ret && n) throw std::bad_alloc();
return ret;
}
void deallocate(T* ptr, const size_t n) {
if (ptr && n) _pool.ordered_free(ptr, n);
}
// for comparing
size_t pool_size() const { return _pool.get_requested_size(); }
private:
Pool& _pool;
};
template <class T, class U> bool operator==(const my_pool_alloc<T> &a, const my_pool_alloc<U> &b) { return a.pool_size()==b.pool_size(); }
template <class T, class U> bool operator!=(const my_pool_alloc<T> &a, const my_pool_alloc<U> &b) { return a.pool_size()!=b.pool_size(); }
Заметки:
На моих компиляторах это работает для обоих std::vector
и Boost’s vector
:
Все пробеги без утечек и убсан / асан чист.
Обратите внимание, как мы повторно используем один и тот же пул с разными контейнерами разного размера структуры и как мы можем даже использовать его с несколькими действующими контейнерами одновременно, при условии, что типы элементов соответствуют размеру запроса (32)
struct A { char data[7]; };
struct B { char data[29]; };
int main() {
//using boost::container::vector;
using std::vector;
Pool pool(32); // 32 should fit both sizeof(A) and sizeof(B)
{
vector<A, my_pool_alloc<A> > v(1024, pool);
v.resize(20480);
};
// pool.release_memory();
{
vector<B, my_pool_alloc<B> > v(1024, pool);
v.resize(20480);
}
// pool.release_memory();
// sharing the pool between multiple live containers
{
vector<A, my_pool_alloc<A> > v(512, pool);
vector<B, my_pool_alloc<B> > w(512, pool);
v.resize(10240);
w.resize(10240);
};
}
Использование профилировщика памяти Valgrind показывает, с release_memory
строки закомментированы как показано:
Комментируя в release_memory()
звонки:
Я надеюсь, что это похоже на то, что вы хотели.
Этот распределитель использует существующие pool
которые делегируют обратно в malloc / free для выделения памяти по требованию. Чтобы использовать его с фиксированным «царством», вы можете использовать simple_segregated_storage
непосредственно. Эта статья выглядит как хороший стартер https://theboostcpplibraries.com/boost.pool
Других решений пока нет …