Защо [] операторът не е const за STL карти?

Измислен пример, в името на въпроса:

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
}

Това винаги ме е притеснявало. Защо операторът [] не е const?


person Runcible    schedule 25.09.2009    source източник
comment
Какво трябва да даде operator[] в случай, че даденият елемент не съществува?   -  person Frerich Raabe    schedule 16.11.2011
comment
@Frerich Raabe: Същото като функцията at член: throw std::out_of_range   -  person Jean-Simon Brochu    schedule 08.08.2017


Отговори (6)


Това е болка и доста жалко, че времето за изпълнение и рамката не могат да помогнат при осигуряването на механизъм, който позволява на разработчика да укаже зареждането на viewstate за контрола
person Alan    schedule 25.09.2009
comment
std::set няма operator[]. - person avakar; 25.09.2009
comment
Това е правилният отговор, но константната версия може да направи същото като члена at. Това е хвърляне на std::out_of_range... - person Jean-Simon Brochu; 08.08.2017
comment
Когато се използва за четене на стойност, няма стойност по подразбиране, която да се предостави. std::vector има оператор за четене [], който е const. map трябва да направи същото. - person wcochran; 16.09.2020
comment
@Jean-SimonBrochu конвенцията във всички контейнери е, че at може да хвърля, а [] не. Не мисля, че си струва да нарушавам тази конвенция. - person Caleth; 25.03.2021

Сега, когато с C++11 можете да имате по-чиста версия, като използвате at()

void MyClass::MyFunction( int x ) const
{
  std::cout << m_map.at(x) << std::endl;
}
person Deqing    schedule 09.08.2013
comment
Ако map има const и non-const at()s - защо да не е същото и за operator[]? като const версията не вмъква нищо, а по-скоро хвърля? (Или връщане на опция, когато std::optional го превръща в стандарт) - person einpoklum; 10.12.2015
comment
@einpoklum Точката на коректността на const е предимно статична проверка по време на компилация. Предпочитам компилаторът да се оплаче, отколкото да хвърли изключение, защото не използвах правилно const обекти. - person Millie Smith; 18.04.2016
comment
@einpoklum Много късно, но за други читатели: две претоварвания, които правят толкова различни неща, би било ужасно. Единствената причина at да се предлага в два вида е, че прави return *this; и единствената разлика между претоварванията е const-ността на върнатата препратка. Действителните ефекти и на двете ats са абсолютно еднакви (тоест няма ефект). - person HTNW; 20.04.2020

Забележка за новите читатели.
Първоначалният въпрос беше за 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
    }
}
person Martin York    schedule 25.09.2009
comment
std::set изобщо няма operator[]. - person Everyone; 19.04.2017

Тъй като operator[] може да вмъкне нов елемент в контейнера, той не може да бъде постоянна членска функция. Имайте предвид, че дефиницията на operator[] е изключително проста: m[k] е еквивалентно на (*((m.insert(value_type(k, data_type()))).first)).second. Строго погледнато, тази членска функция е ненужна: тя съществува само за удобство

person Satbir    schedule 25.09.2009

Индексният оператор трябва да бъде const само за контейнер само за четене (който всъщност не съществува в STL сам по себе си).

Индексните оператори не се използват само за разглеждане на стойности.

person Nick Bedford    schedule 25.09.2009
comment
Въпросът е защо няма две претоварени версии - една const, друга не-const - като напр. std::vector прави. - person Pavel Minaev; 25.09.2009

Ако декларирате вашата членска променлива std::map като променлива

mutable std::map<...> m_map;

можете да използвате неконстантните членски функции на std::map във вашите константни членски функции.

person Anthony Cramp    schedule 25.09.2009
comment
Това обаче е ужасна идея. - person GManNickG; 26.09.2009
comment
API за вашия клас лъже, ако направите това. Функцията твърди, че е const -- което означава, че няма да модифицира никакви членски променливи -- но в действителност може да модифицира члена с данни m_map. - person Runcible; 18.03.2010
comment
mutable може да се използва за членове като std::mutex, кешове и помощници за отстраняване на грешки. Ако картата трябва да се използва като кеш за ускоряване на много скъпа функция за получаване на const, тогава mutable е приемливо. Трябва да внимавате, но това не е ужасна идея сама по себе си. - person Mark Lakata; 29.09.2015