C ++ карта відкидає класифікатори доступу (const)


113

Наступний код каже , що проходячи карту , як constв operator[]відбіркові метод відкидає:

#include <iostream>
#include <map>
#include <string>

using namespace std;

class MapWrapper {
public:
    const int &get_value(const int &key) const {
        return _map[key];
    }

private:
    map<int, int> _map;
};

int main() {
    MapWrapper mw;
    cout << mw.get_value(42) << endl;
    return 0;
}

Це через можливе виділення, яке відбувається в доступі до карти? Не можна жодні функції з доступом до карти оголошувати const?

MapWrapper.cpp:10: error: passing ‘const std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >’ as ‘this’ argument of ‘_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = int, _Tp = int, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, int> >]’ discards qualifiers


Просто нітпік, але mw можна оголосити просто як MapWrapper mw;
luke

Хороший момент - я пишу на двох мовах, тому я прагну нормалізувати синтаксис через них, щоб усі вони помістилися в моїй голові. :)
cdleary

Я можу це оцінити. Будьте уважні, хоча у таких випадках у вас є додаткова конструкція об'єкта та призначення, які не потрібні.
luke

Ще один хороший момент - покладатися на оператора призначення за замовчуванням не є хорошою практикою для публічних прикладів. ;)
cdleary

Відповіді:


152

std::mapРосія operator []не оголошується як constта не може бути пов'язана з її поведінкою:

T & оператор [] (const Key & key)

Повертає посилання на значення, відображене на ключ, еквівалентний ключу, виконуючи вставлення, якщо такого ключа ще не існує.

Як результат, вашу функцію неможливо оголосити const, а використовувати карту operator[].

std::mapfind()Функція '' дозволяє шукати ключ, не змінюючи карту.

find()повертає iterator, або, const_iteratorщо std::pairмістить і ключ ( .first), і значення (.second ).

У C ++ 11 ви також можете використовувати at()для std::map. Якщо елемента не існує, функція видає std::out_of_rangeвиняток, на відміну від operator [].


8
додатково: VALUE = map.find (KEY) -> секунда; Мені довелося дізнатись, що "find ()" повертає ітератор, що є парою типів.
FlipMcF

5
Я додам, що зараз у C11 ви можете використовувати: std :: map :: at (key) та уникати ітератора.
Хуан Беса

3
Цікаво. Я думаю, що C ++ розрізняє lvalue operator[](наприклад foo[bar] = baz) та rvalue operator[](наприклад x = foo[bar]) - останнє, безумовно, може бути const.
Клавдіу

15

З тих пір operator[] не має перевантаженої категорії, що відповідає вимогам const, його не можна безпечно використовувати у функції, призначеної для const. Це, мабуть, тому, що поточне перевантаження було побудовано з метою повернення та встановлення ключових значень.

Натомість ви можете використовувати:

VALUE = map.find(KEY)->second;

або в C ++ 11 ви можете використовувати at()оператор:

VALUE = map.at(KEY);

map.find(KEY)->second; небезпечно, коли значення карт є рядками. Це прагне друкувати сміття, коли КЛЮЧ не знайдено.
сям

1
Це правильно пояснена відповідь, яка йде до суті. Вчора я провів 2 години, намагаючись з’ясувати, що відбувається з подібним випадком. Чи можемо ми погодитися, що повідомлення про помилку в кращому випадку є оманливим? Я міг би бути набагато зрозумілішим, якби у нього не було слова "це" і посилався на const-ness замість більш загального класифікатора .
карнич

11

Не можна використовувати operator[]на карті, що є constтаким методом, який не constє тим, що дозволяє змінювати карту (яку можна призначити _map[key]). Спробуйте скористатися findметодом.


1
У поясненні: що повинен робити оператор карти [], якщо ключ не існує? Якщо карта не const, ключ додається зі значенням, побудованим за замовчуванням. Якщо карта const, що може повернути оператор []? На цьому ключі немає значення.

Це правильно пояснена відповідь, яка йде до суті. Вчора я провів 2 години, намагаючись з’ясувати, що відбувається з подібним випадком. Чи можемо ми погодитися, що повідомлення про помилку в кращому випадку є оманливим? Я міг би бути набагато зрозумілішим, якби у нього не було слова "це" і посилався на const-ness замість більш загального класифікатора .
карнич

7

Деякі новіші версії заголовків GCC (4.1 та 4.2 на моїй машині) мають нестандартні функції функцій членів :: at (), які оголошені const та кидають std :: out_of_range, якщо ключа немає на карті.

const mapped_type& at(const key_type& __k) const

З посилання в коментарі до функції, видно, що це було запропоновано як нова функція-член у стандартній бібліотеці.


Я думаю, це трохи примха. Функція at є частиною майбутнього стандарту, але я не знаходжу в () у поточному.
Себастьян Мах

'at' є частиною C ++ 11.
Етьєн

0

По-перше, вам не слід використовувати символи, що починаються з _, оскільки вони зарезервовані для програми мовлення / компілятора. _Map було б дуже просто помилкою синтаксису на чиємусь компіляторі, і ви нікого не звинувачувати, крім себе.

Якщо ви хочете використовувати підкреслення, поставте його в кінці, а не на початку. Ви, мабуть, помилилися, бо побачили, як це робиться якийсь код Microsoft. Пам’ятайте, вони пишуть власний компілятор, тож вони зможуть уникнути цього. Тим не менш, це погана ідея.

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


5
Ваша думка про _це просто неправильна. Ідентифікатори, що починаються з двох підкреслень ( __example), або ідентифікатори, що починають одну підкреслення та велику літеру ( _Example), зарезервовані. _exampleне зарезервовано.
Етан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.