Пожалуйста, не пытайтесь вникать в смысл последней фразы. Вместо этого просто рассмотрите следующий фрагмент и переходите к дальнейшему объяснению:
template
class allocator {
public:
template
struct rebind{
typedef allocator other;
};
}
В программе, реализующей list
Allocator::rebind
А теперь будьте внимательны. Каждый шаблон распределителя А (например, std::allocato
и т. д.) должен содержать вложенный шаблон структуры с именем rebind
. Предполагается, что rebind
получает параметр U и не определяет ничего, кроме определения типа othe
other
— просто имя для А. В результате listallocator
Может, вы разобрались во всем сказанном, а может, и нет (если думать достаточно долго, вы непременно разберетесь, но подумать придется — знаю по своему опыту). Но вам как пользователю STL, желающему написать собственный распределитель памяти, в действительности не нужно точно понимать суть происходящего. Достаточно знать простой факт: если вы собираетесь создать распределитель памяти и использовать его со стандартными контейнерами, ваш распределитель должен предоставлять шаблон rebind, поскольку стандартные шаблоны будут на это рассчитывать (для целей отладки также желательно понимать, почему узловые контейнеры Т никогда не запрашивают память у распределителей объектов Т).
Ура! Наше знакомство со странностями распределителей памяти закончено. Позвольте подвести краткий итог того, о чем необходимо помнить при программировании собственных распределителей памяти:
•распределитель памяти оформляется в виде шаблона с параметром Т, представляющим тип объектов, для которых выделяется память;
•предоставьте определения типов pointer и reference, но следите за тем, чтобы pointer всегда был эквивалентен Т*, а reference — Т&;
•никогда не включайте в распределители данные состояния уровня объекта. В общем случае распределитель не может содержать нестатических переменных;
•помните, что функциям allocate
передается количество
•обязательно предоставьте вложенный шаблон rebind, от наличия которого зависит работа стандартных контейнеров.
Написание собственного распределителя памяти обычно сводится к копированию приличного объема стандартного кода и последующей модификации нескольких функций (в первую очередь allocate и deallocate). Вместо того чтобы писать базовый код с самого начала, я рекомендую воспользоваться кодом с web-страницы Джосаттиса [23] или из статьи Остерна «What Are Allocators Good For?» [24].
Материал, изложенный в этом совете, дает представление о том, чего
Совет 11. Учитывайте область применения пользовательских распределителей памяти