Ответ 1
Но как узнать, какой распределитель использует контейнер, если он внутренне переустанавливает данный распределитель из параметра шаблона?
Всегда поставляйте конструктору Allocator<T>
(где T
- value_type
контейнера). Контейнер преобразует его в Allocator<U>
, где U
- некоторая внутренняя структура данных контейнера. Allocator
требуется для подачи таких конструкторов преобразования, например:
template <class T> class allocator {
...
template <class U> allocator(const allocator<U>&);
Кроме того, я прочитал, что С++ 11 теперь использует ограниченные распределители, которые позволяют для повторного использования распределителя контейнера для его содержащих контейнеров.
Ну, точнее, С++ 11 имеет адаптер-распределитель, называемый scoped_allocator_adaptor
:
template <class OuterAlloc, class... InnerAllocs>
class scoped_allocator_adaptor : public OuterAlloc
{
...
};
Из С++ 11:
Шаблон класса
scoped_allocator_adaptor
является шаблоном распределителя который указывает ресурс памяти (внешний распределитель), который будет использоваться контейнер (как и любой другой распределитель), а также указывает внутренний ресурс распределителя, который должен быть передан конструктору каждого элемента в контейнере. Этот адаптер создается с помощью одного внешнего и нулевые или более внутренние типы распределителей. Если создается экземпляр только с одним тип распределителя, внутренний распределитель становитсяscoped_allocator_adaptor
, таким образом, используя тот же распределитель ресурс для контейнера и каждый элемент в контейнере и, если сами элементы являются контейнерами, каждый из их элементов рекурсивно. Если создается экземпляр с несколькими распределителями, первый распределитель - это внешний распределитель для использования контейнером, второй распределитель передается конструкторам элементов контейнеров, и, если сами элементы являются контейнерами, третий распределитель передается элементам элементов и т.д. Если контейнеры вложены на глубину, большую, чем количество распределителей, последний распределитель используется, как и в случае с одним распределителем, для любых оставшихся рекурсии. [Примечание:scoped_allocator_adaptor
происходит от внешний распределитель, поэтому он может быть заменен внешним распределителем введите большинство выражений. - конечная нота]
Таким образом, вы получаете только поведение распределенных распределителей, если вы указываете scoped_allocator_adaptor
как распределитель для вашего контейнера.
Как реализуется контейнер с разрешенным областью применения примерно отличается от того, который не знает о контейнерах с областью?
Ключ в том, что контейнер теперь имеет дело с его распределителем через новый класс с именем allocator_traits
, а не напрямую с распределителем. И контейнер должен использовать allocator_traits
для определенных операций, таких как построение и уничтожение value_type
в контейнере. Контейнер не должен напрямую разговаривать с распределителем.
Например, распределители могут предоставить член с именем construct
, который будет строить тип по определенному адресу с использованием заданных аргументов:
template <class T> class Allocator {
...
template<class U, class... Args>
void construct(U* p, Args&&... args);
};
Если распределитель не предоставляет этот член, allocator_traits
предоставит реализацию по умолчанию. В любом случае контейнер должен конструировать все value_type
, используя эту функцию construct
, но используя его через allocator_traits
, а не напрямую используя Allocator
:
allocator_traits<allocator_type>::construct(the_allocator, *ugly details*);
scoped_allocator_adaptor
предоставляет пользовательские функции construct
, которые allocator_traits
будет пересылать, чтобы использовать черты uses_allocator
и передает правильный распределитель вместе с конструктором value_type
. Контейнер остается блаженно не осведомленным об этих деталях. Контейнер должен знать, что он должен построить value_type
с помощью функции allocator_traits construct
.
С подробными сведениями, которые должен иметь контейнер, нужно иметь дело с корректной обработкой контроллеров состояния. Хотя эти детали также рассматриваются, поскольку контейнер не делает никаких предположений, но получает все свойства и поведение через allocator_traits
. Контейнер не может даже предположить, что pointer
- T*
. Скорее, этот тип найден, задав allocator_traits
, что это такое.
Короче говоря, для создания контейнера С++ 11 изучите allocator_traits
. И тогда вы получите бесплатное использование распределенного распределения, когда ваши клиенты используют scoped_allocator_adaptor
.