В настоящее время я ищу лучший способ расширения произвольного стандартного типа распределителя соответствия. Чтобы было ясно: я не хочу писать собственный распределитель. Я просто хочу «добавить» конкретное расширение или поведение к уже существующему. Я создал образец, как это может выглядеть. Обратите внимание, что следующий код только для иллюстрации.
#ifndef HPP_SMART_ALLOCATOR_INCLUDED
#define HPP_SMART_ALLOCATOR_INCLUDED
#include <memory>
#include <map>
template<typename T>
struct allocator_traits;
template<typename T, class allocator_type = std::allocator<T>>
class smart_allocator;
template<>
struct allocator_traits<void>
{
typedef std::allocator<void>::const_pointer const_pointer;
typedef std::allocator<void>::pointer pointer;
typedef std::allocator<void>::value_type value_type;
};
template<typename T>
struct allocator_traits
{
typedef typename std::allocator<T>::const_pointer const_pointer;
typedef typename std::allocator<T>::const_reference const_reference;
typedef typename std::allocator<T>::difference_type difference_type;
typedef typename std::allocator<T>::pointer pointer;
typedef typename std::allocator<T>::reference reference;
typedef typename std::allocator<T>::size_type size_type;
typedef typename std::allocator<T>::value_type value_type;
};
template<class allocator_type>
class smart_allocator<void, allocator_type>
: public allocator_traits<void>
{
public:
template<typename U> struct rebind { typedef smart_allocator<U, typename allocator_type::rebind<U>::other> other; };
};
template<typename T, class allocator_type>
class smart_allocator
: public allocator_traits<T>,
private allocator_type
{
public:
using typename allocator_traits<T>::const_pointer;
using typename allocator_traits<T>::const_reference;
using typename allocator_traits<T>::difference_type;
using typename allocator_traits<T>::pointer;
using typename allocator_traits<T>::reference;
using typename allocator_traits<T>::size_type;
using typename allocator_traits<T>::value_type;
template<typename U> struct rebind { typedef smart_allocator<U, typename allocator_type::rebind<U>::other> other; };
smart_allocator() throw() /*noexcept*/;
smart_allocator(allocator_type const&) throw() /*noexcept*/;
virtual ~smart_allocator() throw();
virtual ~smart_allocator()
{
std::map<pointer, size_type>::iterator i = this->m_map.begin();
while (i != this->m_map.end())
{
this->allocator_type::deallocate(i->first, i->second);
++i;
}
}
pointer allocate(size_type n, allocator_traits<void>::const_pointer hint = 0)
{
pointer p = this->allocator_type::allocate(n, hint);
this->m_map.insert(std::pair<pointer, size_type>(p, n));
return p;
}
void deallocate(pointer p, size_type n) /*noexcept*/
{
std::map<pointer, size_type>::iterator iter = this->m_map.find(p);
if (iter != this->m_map.end())
this->allocator_type::deallocate(iter->first, iter->second);
}
using allocator_type::address;
using allocator_type::construct;
using allocator_type::destroy;
using allocator_type::max_size;
private:
smart_allocator(smart_allocator const&) throw();
smart_allocator& operator=(smart_allocator const&);
std::map<pointer, size_type> m_map;
};
#endif /* HPP_SMART_ALLOCATOR_INCLUDED */
Обратите внимание на следующие примечания:
- Аргумент шаблона allocator_type может быть любым стандартным типом соответствия. Это не ограничивается std :: allocator. Это та же самая техника, которую используют все реализации STL.
- Нам нужно использовать частное наследование при наследовании от allocator_type, потому что ни одна из функций-членов std :: allocator не является виртуальной. Однако std :: allocator & alloc = smart_allocator () не будет делать то, что вы ожидаете.
Как вы думаете, это применимо?