Чому оператор [] не є const для карт STL?


89

Надуманий приклад для питання:

void MyClass::MyFunction( int x ) const
{
  std::cout << m_map[x] << std::endl
}

Це не компілюється, оскільки оператор [] не є const.

Це прикро, оскільки синтаксис [] виглядає дуже чисто. Натомість я маю зробити щось подібне:

void MyClass::MyFunction( int x ) const
{
  MyMap iter = m_map.find(x);
  std::cout << iter->second << std::endl
}

Це мене завжди хвилювало. Чому оператор [] не є const?


5
Що має operator[]дати в разі, якщо даний елемент не існує?
Frerich Raabe

4
@Frerich Raabe: Те саме, що і функція at member: throw std :: out_of_range
Жан-Саймон Брошу

Відповіді:


90

Для std::mapі std::unordered_map, operator[]буде вставляти значення індексу в контейнер, якщо воно раніше не існувало. Це трохи неінтуїтивно, але це так.

Оскільки йому слід дозволити відмову та вставити значення за замовчуванням, оператор не може використовуватися на constекземплярі контейнера.

http://en.cppreference.com/w/cpp/container/map/operator_at


3
std::setне має operator[].
авакар

2
Це правильна відповідь, але версія const може робити те саме, що і член "at". Тобто киньте std :: out_of_range ...
Жан-Саймон Брошу

При використанні для читання значення значення за замовчуванням не надається. std::vectorмає оператор читання, []який є const. mapповинні робити те саме.
wcochran

51

Тепер, коли на C ++ 11 ви можете отримати чистішу версію, використовуючи at ()

void MyClass::MyFunction( int x ) const
{
  std::cout << m_map.at(x) << std::endl;
}

4
Якщо mapє const і non-const at()s - чому б не однаково і для operator[]? при цьому версія const нічого не вставляє, а швидше кидає? (Або повернення необов’язкового, коли std :: optional робить його стандартним)
einpoklum

@einpoklum Точкою правильності const є переважно статична перевірка часу компіляції. Я вважаю за краще, щоб компілятор скаржився, ніж викидав виняток, оскільки я неправильно використовував об’єкти const.
Millie Smith

@einpoklum Дуже пізно, але для інших читачів: мати два перевантаження, які роблять такі різні речі, було б жахливо. Єдина причина atв двох варіантах полягає в тому, що це робить a return *this;, і єдина різниця між перевантаженнями полягає у const-ness повернутого посилання. Фактичні ефекти обох ats абсолютно однакові (тобто відсутність ефекту).
HTNW

28

Примітка для нових читачів.
Початкове питання стосувалося контейнерів STL (не конкретно про std :: map)

Слід зазначити, що для більшості контейнерів існує const-версія оператора [].
Просто std :: map і std :: set не мають const-версії, і це результат базової структури, яка їх реалізує.

Від 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
    }
}

1
std::setне має operator[]взагалі.
Усі

2

Оскільки оператор [] може вставити новий елемент у контейнер, він не може бути функцією-членом const. Зверніть увагу, що визначення оператора [] надзвичайно просто: m [k] еквівалентно (* ((m.insert (value_type (k, data_type ()))). First)). Second. Строго кажучи, ця функція-член непотрібна: вона існує лише для зручності


0

Оператор індексу повинен бути const лише для контейнера, доступного лише для читання (який насправді не існує в STL).

Оператори індексу використовуються не лише для перегляду значень.


6
Питання в тому, чому у нього немає двох перевантажених версій - одна const, інша не-, constяк, наприклад std::vector, є.
Павло Мінаєв

-2

Якщо ви оголосите свою змінну члена std :: map змінною

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

Ви можете використовувати функції не-const-члена std :: map у своїх функціях-членах const.


15
Однак це жахлива ідея.
GManNickG

7
Якщо ви це зробите, API для вашого класу лежить. Функція стверджує, що вона const - це означає, що вона не змінить жодних змінних-членів, - але насправді це може бути зміна елемента даних m_map.
Runcible

2
mutableможе використовуватися для таких членів, як std::mutexкеші та помічники налагодження. Якщо карту слід використовувати як кеш для прискорення дуже дорогої функції const"отримання", тоді mutableце прийнятно. Потрібно бути обережним, але це не страшна ідея сама по собі.
Mark Lakata
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.