Часто пишут что с не-стандартным аллокатором код может работать быстрее, а как вообще написать свой аллокатор?
Ответ
Требования к аллокаторам, и их значения по-умолчанию приведены в главе "Allocator requirements [allocator.requirements]". В этой же главе приводится пример минимального аллокатора:
template
template
Tp* allocate(std::size_t n);
void deallocate(Tp* p, std::size_t n);
};
template
Предполагается, что контейнеры обязаны обращаться к аллокатору не напрямую, а через шаблон std::allocator_traits, который предоставляет значения по-умолчанию, такие как typedef T* pointer;, и т.п.
Однако существующие реализации стандартных библиотек не везде используют allocator_traits.
По этому если мы попробуем например скомпилировать код
std::basic_string
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/basic_string.h:114:41: error: 'rebind' following the 'template' keyword does not refer to a template
typedef typename _Alloc::template rebind<_CharT>::other _CharT_alloc_type;
или
1>S:\MSVS2013\VC\include\xstring(664): error C2903: 'rebind' : symbol is neither a class template nor a function template
В обоих случаях в реализации стандартной библиотеки написано _Alloc::rebind вместо allocator_traits<_Alloc>::rebind
Таким образом, при написании своего аллокатора, надо смотреть на ошибки компиляции, и при необходимости дописывать нужные члены класса.
Ниже приведен пример Arena аллокатора, который компилируется (VC++2013, g++-4.9.2)
#include
class Arena {
public:
Arena() {}
~Arena() {
assert(m_allocations == 0);
}
void* allocate(std::size_t n) {
if (n > m_available) {
m_chunks.emplace_back(100500);
m_available = m_chunks.back().size();
m_memory = &m_chunks.back().front();
}
auto mem = m_memory;
m_available -= n;
m_memory += n;
++m_allocations;
return mem;
}
void deallocate(void* p, std::size_t n) {
--m_allocations;
auto mem = (unsigned char*)p;
if (mem + n == m_memory) {
m_memory = mem;
m_available += n;
}
}
private:
std::deque
template
using Traits = std::allocator_traits
#if !defined _MSC_VER
// libstdc++ использует конструктор по умолчанию:
// __a == _Alloc()
ArenaAllocator() : m_arena(nullptr) {}
// libstdc++ требует следующие определения
using size_type = typename std::allocator
explicit ArenaAllocator(Arena& arena) : m_arena(&arena) {}
template
T* allocate(std::size_t n) { return (T*)m_arena->allocate(n * sizeof(T)); }
void deallocate(T* p, std::size_t n) { m_arena->deallocate(p, n * sizeof(T)); }
// требуется в VC++ и libstdc++
template
Arena* m_arena;
};
template
#include
#include
Комментариев нет:
Отправить комментарий