Надуманный пример, ради вопроса:
void MyClass::MyFunction( int x ) const
{
std::cout << m_map[x] << std::endl
}
Это не будет компилироваться, поскольку оператор [] не является константой.
Это прискорбно, поскольку синтаксис [] выглядит очень чистым. Вместо этого я должен сделать что-то вроде этого:
void MyClass::MyFunction( int x ) const
{
MyMap iter = m_map.find(x);
std::cout << iter->second << std::endl
}
Меня это всегда беспокоило. Почему оператор [] не является константой?
operator[]
дать, если данного элемента не существует?Ответы:
Для
std::map
иstd::unordered_map
,operator[]
вставит значение индекса в контейнер , если он ранее не существовал. Это немного не интуитивно, но так оно и есть.Поскольку необходимо разрешить сбой и вставить значение по умолчанию, оператор не может использоваться в
const
экземпляре контейнера.http://en.cppreference.com/w/cpp/container/map/operator_at
источник
std::set
не имеетoperator[]
.std::vector
имеет оператор чтения,[]
то естьconst
.map
должен делать то же самое.Теперь, когда с C ++ 11 вы можете получить более чистую версию, используя at ()
void MyClass::MyFunction( int x ) const { std::cout << m_map.at(x) << std::endl; }
источник
map
есть const и неконстантныеat()
s - почему не то же самое и дляoperator[]
? с версией const ничего не вставляет, а бросает? (Или возвращение необязательного, когда std :: optional превращает его в стандарт)at
бывает двух видов, потому что она выполняет areturn *this;
, и единственная разница между перегрузками - этоconst
-ность возвращаемой ссылки. Фактические эффекты обоихat
s одинаковы (то есть никакого эффекта).Примечание для новых читателей.
Первоначальный вопрос касался контейнеров STL (а не конкретно std :: map)
Следует отметить, что в большинстве контейнеров есть константная версия оператора [].
Просто std :: map и std :: set не имеют константной версии, и это является результатом базовой структуры, которая их реализует.
Из std :: vector
reference operator[](size_type n) const_reference operator[](size_type n) const
Также для вашего второго примера вы должны проверить, не удается ли найти элемент.
void MyClass::MyFunction( int x ) const { MyMap iter = m_map.find(x); if (iter != m_map.end()) { std::cout << iter->second << std::endl } }
источник
std::set
совсем нетoperator[]
.Поскольку operator [] может вставлять новый элемент в контейнер, он не может быть константной функцией-членом. Обратите внимание, что определение operator [] чрезвычайно простое: m [k] эквивалентно (* ((m.insert (value_type (k, data_type ())). First)). Second. Строго говоря, эта функция-член не нужна: она существует только для удобства.
источник
Оператор индекса должен быть константным только для контейнера, доступного только для чтения (который на самом деле не существует в STL как таковой).
Операторы индекса используются не только для просмотра значений.
источник
const
и другойconst
- как, например,std::vector
есть.Если вы объявляете переменную члена std :: map изменяемой
mutable std::map<...> m_map;
вы можете использовать неконстантные функции-члены std :: map в своих константных функциях-членах.
источник
mutable
может использоваться для таких членов, какstd::mutex
кеши и помощники отладки. Если карта будет использоваться в качестве кеша для ускорения очень дорогогоconst
«получения», тоmutable
это приемлемо. Вам нужно быть осторожным, но само по себе это неплохая идея.