Я думаю, что часть вопроса исходит из предположения, что распределители полезны. Распределители (по крайней мере до C ++ 11) были чем-то вроде позднего дополнения к STL :
Люди хотели контейнеры, независимые от модели памяти, что было несколько чрезмерно, потому что язык не включает модели памяти. Люди хотели, чтобы библиотека предоставила некоторый механизм для абстрагирования моделей памяти. В более ранних версиях STL предполагалось, что размер контейнера можно выразить как целое число типа size_t
и что расстояние между двумя итераторами имеет тип ptrdiff_t
. И теперь нам сказали, почему бы тебе не абстрагироваться от этого? Это высокий заказ, потому что язык не абстрагируется от этого; Массивы C и C ++ не параметризованы этими типами. Мы изобрели механизм, называемый «распределитель», который инкапсулирует информацию о модели памяти. Это вызвало серьезные последствия для каждого компонента в библиотеке. Вы можете спросить, какие модели памяти имеют отношение к алгоритмам или интерфейсам контейнеров. Если вы не можете использовать такие вещи, как size_t
, вы также не можете использовать такие вещи, как T*
из-за разных типов указателей (T*
, T huge *
и т. Д.). Тогда вы не можете использовать ссылки, потому что с разными моделями памяти у вас есть разные типы ссылок. В библиотеке произошли огромные последствия.
К сожалению, они оказались некачественными :
Я изобрел распределители для работы с архитектурой памяти Intel. Теоретически они не такие уж плохие идеи - имеют слой, который инкапсулирует все элементы памяти: указатели, ссылки, ptrdiff_t
, size_t
. К сожалению, они не могут работать на практике. Например,
vector<int, alloc1> a(...);
vector<int, alloc2> b(...);
теперь вы не можете сказать:
find(a.begin(), a.end(), b[1]);
b[1]
возвращает alloc2::reference
, а не int&
. Это может быть несоответствие типов. Необходимо изменить способ работы базового языка со ссылками, чтобы сделать распределители действительно полезными.
typedef reference
предназначен для возврата того, что эквивалентно T&
для рассматриваемого распределителя. На современных архитектурах это, вероятно, T&
. Однако предполагалось, что на некоторых архитектурах это может быть что-то другое (например, компилятору, ориентированному на архитектуру с указателями «ближний» и «дальний»), может потребоваться специальный синтаксис для ссылок «ближний» и «дальний»). К сожалению, эта блестящая идея оказалась менее чем блестящей. C ++ 11 вносит существенные изменения в распределители - добавляя выделенные области - и модель памяти. Я должен признать, что не знаю достаточно об изменениях в C ++ 11 w.r.t. Распределители, чтобы сказать, становится ли все лучше или хуже.
Рассматривая комментарии к исходному вопросу, поскольку в стандарте фактически не указывается, как контейнеры должны быть реализованы (хотя в стандарте действительно предъявляется так много требований к поведению контейнеров, что он может также ...), любой тип, который вы вводите как reference
, должен иметь поведение T&
, на которое кто-то может положиться при реализации контейнера: объект типа reference
должен быть прозрачным псевдонимом исходного объекта, назначение которого должно изменить значение исходного объекта без нарезки, нет необходимости поддерживать "переустановку" reference
, взятие адреса reference
должно возвращать адрес исходного объекта и т. д. Если это вообще возможно, оно должно на самом деле быть T&
; и единственный случай, который я могу себе представить, где это было бы невозможно, было бы, если бы вы выделяли память, которой вы не могли манипулировать с помощью указателей или ссылок (например, если «память» была на самом деле на диске, или если память была на самом деле размещены на отдельном компьютере и доступны по сети с помощью вызовов RPC и т. д.).