Подтвердить что ты не робот

Почему вызывается Allocator:: reference?

Итак, я смотрел спецификацию std::vector и заметил, что reference typedef изменен с Allocator::reference на С++ 03 до value_type& на С++ 11. Я был удивлен, поэтому я начал смотреть глубже.

В С++ 03 §20.1.5 [lib.allocator.requirements] есть таблица 32, в которой X::reference определяется как T&, а X::const_reference определяется как T const&.

Однако в С++ 11 §17.6.3.5 [allocator.requirements] есть таблица 28, в которой отсутствуют reference и const_reference.

Далее мы добавили в С++ 11 §20.6.8 std::allocator_traits, который не включает reference. Но §20.6.9 std::allocator делает.

Наконец, существует §23.2.1 [container.requirements.general], которые определяют X::reference как "lvalue of T" и X::const_reference как "const lvalue of T".

Итак, я googled и нашел этот документ (1, 2) который предлагает удалить reference из требований распределителя, но в нем не упоминается никаких оснований. Но есть также проблема LWG, которая выступает против изменения.

Кроме того, я нашел интервью с Александром Степановым, в котором он рассказывает, как reference инкапсулирует макет памяти для конкретной машины и Herb Sutter post, в котором он говорит о приеме указателей на элементы контейнера, требования к контейнерам и как std::vector<bool> не является контейнером.

Итак, что вы думаете обо всем этом? Был ли полезен reference, он служил ему цели? Как "причудливые" ссылки соответствуют стандарту? Является ли это смелым шагом, чтобы полностью устранить их, сделать более строгие требования к контейнерам и отказаться от std::vector<bool>?

4b9b3361

Ответ 1

В интервью с Александром Степановым он упоминает, что во время предложения добавить STL в стандартную библиотеку ему было предложено создать абстракцию из памяти модель. Таким образом, появились распределители. В LWG проблема есть пример реализации, где reference пользовательского распределителя определяется как T __far&.

Но по причинам, неизвестным, потому что у меня не так много времени на поиск, стандарт С++ 03 имеет следующий текст в §20.1.5 p4:

Реализации контейнеров, описанных в этом Международном стандарте, допускают, что их параметр шаблона Allocator соответствует следующим двум дополнительным требованиям, кроме тех, что указаны в таблице 32.

- Все экземпляры данного типа распределителя должны быть взаимозаменяемыми и всегда сравнивать равными друг друга.

- указатель членов typedef, const_pointer, size_type и difference_type требуется, чтобы быть T *, T const *, size_t и ptrdiff_t соответственно.

Это эффективно нарушает способность диспетчера модели пользовательской памяти взаимодействовать со стандартными контейнерами.

Во время поиска всех документов до С++ 11, в которых упоминается слово "распределитель", я нашел большой консенсус по удалению этих слов из Стандарта. Наконец, этот документ предлагает удалить их со следующим комментарием:

Слова ласки исчезли. Поднимите свой стакан и сделайте тост.

Победа? Можем ли мы окончательно разобраться с нашими моделями памяти? Не так много. Помимо прочего, в том же документе предлагается удалить reference из требований распределителя. И похоже, что он был принят в Стандарт.

Проблема LWG Я уже упоминал об этом, но он был закрыт следующим утверждением:

Отсутствие консенсуса относительно изменения

Итак, похоже, что первоначальная цель распределителей сегодня не так важна. Вот что Wikipedia должно сказать:

Текущая цель распределителей - дать программисту контроль над распределением памяти внутри контейнеров, а не адаптировать модель адреса базового оборудования. Фактически, пересмотренный стандарт исключил способность распределителей представлять расширения для модели адреса С++, формально (и преднамеренно) устраняя их первоначальную цель.

Наконец, Container::reference не имеет ничего общего с распределителями. Он был создан для использования проксированных коллекций которые фактически не являются контейнерами. Так что это здесь, чтобы остаться. Кстати, похоже, что это еще один пример того, как последние слова в Стандарте противоречат оригинальным намерениям.

Ответ 2

Потому что этот вложенный typedef лишний. Эффективный STL Скотта Мейера, стр. 49:

Стандарт явно позволяет библиотечным реализаторам предположить, что каждый указатель распределителя typedef является синонимом T * и каждый ссылочный ссылочный номер-распределитель такой же, как T &

Ответ 3

http://en.wikipedia.org/wiki/Allocator_(C%2B%2B)

"Первоначально они были предназначены для того, чтобы сделать библиотеку более гибкой и независимой от базовой модели памяти, что позволяет программистам использовать пользовательский указатель и ссылочные типы с библиотекой. Однако в процессе принятия STL в стандарт С++, комитет по стандартизации С++ осознал, что полная абстракция модели памяти будет приводить к неприемлемым наказаниям за исполнение. Чтобы исправить это, требования распределителей были сделаны более ограничительными. В результате уровень настройки, предоставляемый распределителями, более ограничен, чем первоначально предусмотренный Степановым".

Первоначально они были предназначены для абстрагирования самой памяти, позволяющей выделять память, скажем, другую машину через Интернет и подключение к Интернету, и копировать данные туда и обратно с помощью указателей/ссылок, чтобы отслеживать, что происходит в реальном времени. Аналогично, можно сделать Java-подобный GC в чистом С++. Эта абстракция казалась удивительной идеей!

Однако это привело к штрафам за исполнение, которые в то время считались неприемлемыми. Кроме того, если вы думаете об этом, почти невозможно работать в коде. Каждый void func(const string&) должен быть превращен в template<class allocator> void func(allocator::reference), который является невыводимым контекстом, поэтому вам нужно будет явно написать распределитель в вызове функции (func<std::allocator<std::string>::const_reference>(username)), который никто не сделает, что сделало бы GC не работает должным образом. В настоящее время распределители просто абстрагируют выделение/освобождение памяти.