Почему только неконстантные карты обеспечивают прямой поиск элементов в виде массива? - PullRequest
6 голосов
/ 29 ноября 2011

Я читаю:

Стандартная библиотека C ++: учебное пособие и справочник Николая М. Йоссуттиса

Это моя книга, когда ясобираюсь использовать некоторые механизмы STL любым существенным способом.Как бы то ни было, я быстро перечитал главы о std :: map и связанных с ними алгоритмах и заметил предложение, о котором раньше не думал:

Непостоянные карты предоставляют оператор индекса для прямого доступа к элементу,Однако индекс оператора индекса не является неотъемлемой позицией элемента.... и т. д.

Почему только неконстантные карты можно использовать в ассоциативном массиве, например?Кажется, что в этом случае было бы довольно просто предоставить семантику только для чтения.Я предполагаю, что исключения будут возможны, если вы попытаетесь получить элемент с ключом, который не существует (если вы не можете добавить новый ключ / значение на карту, если его константа).

Я быхотел бы понять причины этого, если кто-то может пролить свет :) спасибо!

Ответы [ 4 ]

11 голосов
/ 29 ноября 2011

Почему в ассоциативном массиве можно использовать только непостоянные карты образом?

Поскольку эти операторы возвращают ссылку на объект, связанный с конкретным ключом. Если контейнер еще не содержит такого объекта, operator[] вставляет объект по умолчанию. Теперь, если контейнер постоянный, вы не можете вставлять в него какие-либо объекты и не можете возвращать ссылку на несуществующие объекты, поэтому эти операторы доступны только для неконстантных контейнеров.

Создание исключения в этом случае, конечно, возможно, но это не лучший способ приблизиться к довольно общим случаям, когда объект для данного ключа не существует. По сути, исключения являются чрезвычайно дорогими и предназначены для исключительных ситуаций, а вышеперечисленное - нет, поэтому оно того не стоит.

Лучшим способом было бы вернуть итератор, но тогда пользователь должен будет проверить, не является ли он "концом", что сделает случай использования похожим на вызов find (), поэтому бесполезным. Также возможен возврат итераторов или указателей для контейнеров только для констант, но это немного нарушает семантику и сбивает с толку.

8 голосов
/ 29 ноября 2011

В C ++ 11 вы можете использовать at(), чтобы получить поведение «получить сопоставленное значение, иначе выбросить исключение».Перегрузка operator[] для выполнения двух разных действий (например, вставка новой пары или бросок) в зависимости от того, является ли карта постоянной, будет слишком запутанной и подверженной ошибкам.

1 голос
/ 29 ноября 2011

[] оператор изменяет карту, если ключ не существует.

Если ключ не существует, карта создает новую запись с ключом и значением по умолчанию для связанного значения и возвращает его ссылку.Чтобы это произошло, operator[] должна быть неконстантной функцией, что означает, что она не может работать с const экземпляром std::map.

1 голос
/ 29 ноября 2011

Оператор [] изменяет контейнер: если ключ не существует, он будет создан:

return m[1];      // **creates** m[1] if it doesn't exist

return *m.find(1) // UB if m[1] doesn't exist (dereferencing m.end())

Кроме того, [] всегда возвращает непостоянную ссылку, поэтому вы можете сказать m[1] = 2;. С другой стороны, find() возвращает итератор, константа которого совпадает с константой самой карты:

map_t m;
*m.find(1) = 2;    // Only OK if m[1] exists
// *const_cast<map_t const &>(m).find(1) = 2;  // error
...