STL: аллокаторы - миф?
От: orangy Россия
Дата: 16.09.02 15:58
Оценка: 28 (3)
Вот сколько ни вожусь с этими аллокаторами, всё одного понять не могу. Зачем они нужны в таком виде?
Реальной области памяти с их помощью не ввести (ссылочного типа не сделать), только разные приплясывания на тему основной памяти. Эффективного распределения в общем случае добиться весьма трудно, в частности rebind требует от аллокатора фактически произвольного распределения памяти при отсутствии данных экземпляра аллокатора или же тем более сложных приплясываний при наличии данных экземпляра (например идентификатора пула или что-то типа этого). Вообще, стандартные аллокаторы (в том числе и по мнению Страуструпа) не должны иметь данных экземпляра. Безумные пляски с аллокаторами можно встретить и в SGI-реализации STL:

>// Note that standard-conforming allocators use many language features

>// that are not yet widely implemented. In particular, they rely on
>// member templates, partial specialization, partial ordering of function
>// templates, the typename keyword, and the use of the template keyword
>// to refer to a template member of a dependent type.

Пример у Страуструпа с Pool_alloc работает на массивах, но вот работать этот аллокатор для списков не будет (без переделок) — он распределяет данные размера sizeof(T), а в списке нужно sizeof(T) + delta, где delta скорее всего 2*sizeof(list_node<T>*) (код условен). Таким образом мы сталкиваемся с двумя одновременными "хинтами" к аллокатору (понятно, что общий аллокатор пойдёт в любом случае, но он не эффективен в частностях).
Первый хинт исходит от пользователя. Например, пользователь может знать, что он напихает кучу элементов в список, что-то с ними поделает, а потом удалит все сразу. Очевидно, в данном случае эффективнее всего работа с пулами, где память распределяется просто как в стеке (путём движения указателя верха и аллокации страниц по мере необходимости, если заранее их число не известно), а потом удаление всего сразу.
Второй хинт исходит от контейнера. Список точно знает, что ему всегда нужно аллоцировать память одинаковыми кусками и это можно эффективно использовать. Другие контейнеры могут предлагать свои хинты. Таких хинтов не так уж и много (даже использование описаных двух резко увеличит эффективность), остаётся только выбрать нужный аллокатор, удовлетворяющий большинству [наиболее важных] хинтов. Как это сделать? Как оставить пользователю возможность всё-таки управлять аллокаторами, так как нужно ему? И не озадачивать пользователя сверх меры, когда это не нужно? Простое — просто, сложное возможно.

Дальнейшие мои размышления были прерваны сном и чтением Страуструпа и стандарта на ночь, дабы всё-таки въехать в глубинную мысль (ибо очень умные люди)... Так и не понял, наверное тормоз я какой-то, и начал думать дальше...
Пришёл примерно к следующим выводам. Во-первых, имеет смысл отделить спецификацию памяти (типы pointer, reference, методы construct, etc) от непосредственно аллокатора. Потому, что в одной памяти могут работать разные аллокаторы, но объекты при этом должны жить счастливо. Во-вторых, в контейнеры передавать некую фабрику аллокаторов, умеющую генерировать аллокаторы по хинтам. Эта фабрика может быть вообще синглетоном, может создаваться по мере необходимости или их может быть много на разные случаи жизни. Важно то, чтобы фабрика умела обрабатывать хинты кумулятивно. Например, пользователь выставляет "много аллокаций, разом удалить", список говорит "аллокации одинакового размера", фабрика выдаёт адекватный аллокатор.

Понятно, что это чистой воды теоретизирование, что фактически имплементация может отличаться, что может быть и на текущей модели аллокаторов можно такое сделать (поправив реализацую STL соответственно)... Но больше всего меня смущает :
Implementations of containers described in this International Standard 
are permitted to assume that their Allocator template parameter meets 
the following two additional requirements:
— All instances of a given allocator type are required to be interchangeable 
and always compare equal to each other.
— The typedef members pointer, const_pointer, size_type, 
and difference_type are required to be T*, T const*, size_t, and ptrdiff_t, 
respectively.

Фиг с ним со вторым требованием, пока мы все чаще всего живём в обычной памяти, кроме того ссылок-то и не сделать. А вот с первым-то что делать?

Вобщем такой вот странный и задумчивый постинг. Можно смело его выбросить
... << J 1.0 alpha 4 >>
"Develop with pleasure!"
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.