patterncppMinor
Simple Pool Allocator
Viewed 0 times
poolallocatorsimple
Problem
This is a simple pool allocator, based (to at least some degree) on a previous answer. The basic idea is pretty simple: allow a user to allocate objects of some type quickly (in relatively large contiguous chunks) and only free objects when the allocator itself is freed, then destroy all the objects and free the memory they occupy.
I'd welcome any and all suggestions (including adding specialization to avoid executing destructors on trivially destructible types). I'm also wondering (sort of thinking out loud) whether it would make sense to use a geometric allocation strategy, similar to
#include
#include
template
class Allocator {
const size_t pool_size = T_per_page * sizeof(T);
std::vector pools;
size_t next_pos;
void alloc_pool() {
next_pos = 0;
void *temp = operator new(pool_size);
pools.push_back(static_cast(temp));
}
public:
Allocator() {
alloc_pool();
}
T* operator()(T const &x) {
if (next_pos == T_per_page)
alloc_pool();
T *ret = new(pools.back() + next_pos) T(x);
++next_pos;
return ret;
}
~Allocator() {
while (!pools.empty()) {
T *p = pools.back();
for (size_t pos = T_per_page; pos > 0; --pos)
p[pos - 1].~T();
operator delete(static_cast(p));
pools.pop_back();
}
}
};
#ifdef TEST
struct list_node {
int val;
list_node *next;
list_node(int x) : val(x), next(nullptr) {}
friend std::ostream &operator alloc;
int main() {
for (int i = 0; i < 20; i++) {
list_node *j = alloc(i + 1000);
}
}
#endifI'd welcome any and all suggestions (including adding specialization to avoid executing destructors on trivially destructible types). I'm also wondering (sort of thinking out loud) whether it would make sense to use a geometric allocation strategy, similar to
std::vector's, to (perhaps) fit allocation time to size more effectively.Solution
Allocation of raw memory
Rather than using
Constructor
It may be more efficient to use normal constructor than the copy constructor. You should also provide the move constructor.
Destructor
Yes you can optimize the destructor if
Rather than using
operator new you could use std::get_temporary_buffer(n). This allocates contiguous "correctly aligned" storage for enough memory to store approx n objects of type T (its non binding contract read documents).Constructor
It may be more efficient to use normal constructor than the copy constructor. You should also provide the move constructor.
T* operator()(T&& x);
T* operator()(T const &x);
template
T* operator()(Args... args);Destructor
Yes you can optimize the destructor if
Ts destructor is guranteed to do nothing.template
struct SimpleDestructableTrivialy
{
static constexpr bool value = std::is_trivially_destructible::value;
};
template::value>
class SimpleDestroy
{
public:
void destroyElements(T* p, std::size_t T_per_page);
};
template
class SimpleDestroy
{
public:
void destroyElements(T* p, std::size_t T_per_page) {}
};
template
class SimpleDestroy
{
public:
void destroyElements(T* p, std::size_t T_per_page)
{
for (size_t pos = T_per_page; pos > 0; --pos)
p[pos - 1].~T();
}
};Code Snippets
T* operator()(T&& x);
T* operator()(T const &x);
template<typename... Args>
T* operator()(Args... args);template<typename T>
struct SimpleDestructableTrivialy
{
static constexpr bool value = std::is_trivially_destructible<T>::value;
};
template<typename T, bool = SimpleDestructableTrivialy<T>::value>
class SimpleDestroy
{
public:
void destroyElements(T* p, std::size_t T_per_page);
};
template<typename T>
class SimpleDestroy<T, true>
{
public:
void destroyElements(T* p, std::size_t T_per_page) {}
};
template<typename T>
class SimpleDestroy<T, false>
{
public:
void destroyElements(T* p, std::size_t T_per_page)
{
for (size_t pos = T_per_page; pos > 0; --pos)
p[pos - 1].~T();
}
};Context
StackExchange Code Review Q#127258, answer score: 7
Revisions (0)
No revisions yet.