2010-03-17 3 views
4

Следующий код работает отлично:Почему мы не можем иметь неизменный вариант оператора [] для отображения

std::map<int, int>& m = std::map<int, int>(); 
int i = m[0]; 

Но не следующий код:

// error C2678: binary '[' : no operator... 
const std::map<int, int>& m = std::map<int, int>(); 
int i = m[0]; 

Большую часть времени я предпочитают, чтобы сделать большую часть моего материала, чтобы стать непреложным, из-за причины:

http://www.javapractices.com/topic/TopicAction.do?Id=29

Я смотрю на исходный код карты. Он имеет

mapped_type& operator[](const key_type& _Keyval) 

Есть ли причина, почему станд :: карта не в состоянии обеспечить

const mapped_type& operator[](const key_type& _Keyval) const 
+2

Теперь, когда Roger Pate установил меня прямо на мой (теперь удаленный) неверный ответ, я нахожу вопрос гораздо интереснее - почему бы не '' const '' operator [] ', который бросает (или имеет неопределенное поведение) если запись отсутствует на карте? –

+0

@ Майкл: Я полностью согласен. Я никогда не думал «ну просто использовать находку и проверку!» был большой частью ответа; это неуклюже. 'at' выдает исключение в' vector', почему cant 'operator [] const' выдает исключение в' map'? – GManNickG

ответ

4

Оператор [] создаст запись, если она не существует на карте. Это невозможно, если оператор реализован для карты const. Это объяснение в :

индексация карты добавляет элемент по умолчанию , когда ключ не найден. Следовательно, нет версии оператора [] для карт const. Кроме того, подписка может быть используется, только если тип mapped_type (значение ) имеет значение по умолчанию. Если программист просто хочет увидеть, присутствует ли ключ , операцию find() (§17.4.1.6) можно использовать для поиска ключа без изменения карты.

1

оператор [] вставку, если ключ не найден, поэтому он не может быть константным членом.

6

Причина в том, что семантика std::map гласит, что если вы попытаетесь получить доступ к элементу с ключом, который не существует, ключ создается с построенным по умолчанию элементом. Другими словами, m[0] создаст int в местоположении 0, если он еще не существует. Очевидно, что это несовместимо с картой const.

Вы можете сказать: «Хорошо, сделайте const версию operator[], и пусть это не так!», Но есть две проблемы: разница в семантике будет неочевидной и запутанной, и неясно, что именно должно если вы попытаетесь получить доступ к ключу, который не существует (выведите исключение?).

Вместо этого вам нужно использовать метод find() на карте, который вернет итератор, указывающий на пару ключей/значений, которые вы ищете. Поиск в точности такой же эффективный, как и operator[], его можно использовать для сопоставлений const (в этом случае возвращает константный итератор), и он вернет итератор end(), если ключ не существует.

+0

Я не уверен, чтобы подписаться на 'confusing' аргумент, поскольку, как продемонстрировал этот пользователь, он запутан, как и он. И 'map.find (key) -> second' не так хорош, как' map [key] 'is. Если все поведение 'undefined' уже включено, еще один не будет таким пустым: p –

+0

Что касается разрешения неопределенного поведения здесь, это означает, что с картой неизвестного содержимого вы всегда должны сначала проверить, прежде чем искать избегайте этого, что может быть не особенно умным шаблоном использования. – visitor

+0

@Matthieu Я согласен с тем, что текущее поведение не является * интуитивным *, но оно последовательное и, следовательно, не сбивает с толку, как только вы узнали, что это такое. Имея две версии 'operator []', одна из которых гарантированно всегда работает, а другая из них может вызывать исключение или вызывать неопределенное поведение в некоторых обстоятельствах и иметь единственное различие в том, является ли базовый объект const, будет сбивать с толку, потому что изменение константы переменной в другом месте может кардинально изменить поведение программы, не вызывая ошибок или предупреждений во время компиляции. –

2

У этого есть неизменяемая версия, и это называется find().

Смежные вопросы