Во-первых, технически унарный оператор *
в этом случае оценивается как lvalue.Однако термин lvalue в C в основном обозначает то, что имеет местоположение (адрес) в хранилище (памяти).В терминологии C ++ четными функциями являются lvalues .Итак, опять же, в вашем примере выше унарный *
дает lvalue.Вы можете взять адрес этого lvalue, если вы хотите это сделать, т.е. вы можете оценить &*i
, &i->first
и &i->second
(при условии, что встроенный унарный &
).
Во-вторых, поскольку ваш исходный пример включает в себя присваивание, вы должны говорить о изменяемых значениях .Видите ли, свойство быть lvalue само по себе очень мало связано с назначаемостью.Чтобы использовать встроенный оператор присваивания, вам нужно изменить значение lvalue .То, что вы получаете от разыменованного итератора, это value_type
из std::map
.Как вы уже знаете, это пара с квалифицированным первым членом.Это автоматически делает первый член неизменяемым, и это делает всю пару неизменяемой встроенным оператором присваивания.Второй член пары является изменяемым, как вы уже заметили.
Итак, еще раз, оператор разыменования в этом случае возвращает lvalue.Это lvalue не модифицируемо в целом, и его первый член также не модифицируем.Его второй член - модифицируемое lvalue.
Что касается вашего предположения о том, как хранятся элементы std::map
, я бы сказал, что в типичной реализации они будут храниться как pair<const K, V>
объекты, то есть именно то, чтооператор разыменования оценивается как.Обычно карте не нужно изменять ключевую часть пары после ее инициализации, поэтому не должно возникать никаких проблем с тем фактом, что первый член пары является константно-квалифицированным.