Що станеться, якщо я прочитаю значення карти там, де ключа не існує?


84
map<string, string> dada;
dada["dummy"] = "papy";
cout << dada["pootoo"];

Я спантеличений, бо не знаю, вважається це невизначеною поведінкою чи ні, як дізнатися, коли я запитую ключ, якого не існує, чи просто використовувати замість цього find?

Відповіді:


89

У map::operator[]пошуках структури даних для значення , відповідні заданого ключ, і повертає посилання на нього.

Якщо він не може його знайти, він прозоро створює для нього сконструйований елемент за замовчуванням. (Якщо ви не хочете такої поведінки, ви можете використовувати map::atфункцію замість цього.)

Ви можете отримати повний перелік методів std :: map тут:

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

Ось документація map::operator[]з поточного стандарту C ++ ...

23.4.4.3 Доступ до елемента карти

T& operator[](const key_type& x);

  1. Ефекти: Якщо на карті немає ключа, еквівалентного x, вставляє value_type (x, T ()) на карту.

  2. Потрібно: type_type повинен бути CopyConstructible, а mapped_type - DefaultConstructible.

  3. Повертає: Посилання на mapped_type, що відповідає x у * this.

  4. Складність: логарифмічна.

T& operator[](key_type&& x);

  1. Ефекти: Якщо на карті немає ключа, еквівалентного x, вставляє value_type (std :: move (x), T ()) на карту.

  2. Потрібно: mapped_type має бути DefaultConstructible.

  3. Повертає: Посилання на mapped_type, що відповідає x у * this.

  4. Складність: логарифмічна.


Я насправді ніде не знайшов у стандарті, що б там було сказано. Принаймні, не на 23.3.1.2 [lib.map.access] чи деінде ще, що я пам’ятаю перевірити. EDIT: Очевидно, я дивився на стару версію стандарту. Моя помилка.
Влад Чобану,

@VladCiobanu: Вище 23.4.4.3 скопійовано дослівно. Чи використовуєте ви поточну версію ISO/IEC 14882:2011(E)?
Ендрю Томазос,

21

Якщо ви спробуєте отримати доступ до key valueвикористовуваного оператора індексу [], може статися 2 речі:

  1. Карта містить це key. Тож він поверне відповідне key value.
  2. Карта не містить key. У цьому випадку він автоматично додасть а keyна карту за допомогою null value.

"pootoo"ключ не існує на вашій карті. Тому він автоматично додасть це за keyдопомогою value = ""(порожній рядок). І ваша програма надрукує порожній рядок.

Тут розмір карти збільшиться на 1.

Для пошуку ключа можна скористатися map_name.find(), який повернеться, map_name.end()якщо ключа не існує. І ніяких додаткових keyдодавати не буде.

Ви можете використовувати []оператор, коли ви хочете встановити значення ключа.


7

Це не невизначена поведінка. Якщо operator []не знаходить значення для наданого ключа, він вставляє його в цю позицію.


6

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


2

operator[]Для mapповернення неконстантная посилання і ви можете призначити з допомогою цього в тому , як ви показали на другій лінії. Доступ таким чином створить елемент valueтипу типу, виконаний за замовчуванням .

Якщо ви хочете знайти елемент пошуку, це кращий спосіб

iterator find ( const key_type& x )

(або альтернатива const), яка поверне ітератор, рівний, <map>.end()якщо він не знаходить ключ, або якщо ви просто хочете знати, чи є він у колекції, яку ви можете використовувати

size_type count ( const key_type& x ) const

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


1

Якщо оператор [] не знаходить значення для наданого ключа, він вставляє його в цю позицію.

Але ви повинні зауважити, що якщо ви відвідаєте not exist keyта викличете його функцію-члена, як-от mapKV [not_exist_key] .member_fun (). Програма може вийти з ладу.

Наведу приклад, тестовий клас, як показано нижче:

struct MapValue{
    int val;

    MapValue(int i=0){
        cout<<"ctor: "<<i<<endl; val = i;
    }

    ~MapValue(){
        cout<<"dtor: "<<val<<endl;
    }

    friend ostream& operator<<(std::ostream& out, const MapValue& mv){
        cout<<"MapValue: "<<mv.val<<endl;
    }

    string toString(){
        cout<<"MapValue: "<<val<<endl;
    }
};

Тестовий код:

cout<<"-------create map<int, MapValue>-------"<<endl;

map<int, MapValue> idName{{1, MapValue(1)}, {2, MapValue(2)}};

cout<<"-----cout key[2]-----"<<endl;
cout<<idName[2]<<endl;

cout<<"-----cout key[5]-----"<<endl;
cout<<idName[5]<<endl;

cout<<"------- runs here means, does't crash-------"<<endl;

Результат, як показано нижче:

-------create map<int, MapValue>-------
ctor: 1
ctor: 2
dtor: 2
dtor: 1
dtor: 2
dtor: 1
-----cout key[2]-----
MapValue: 2

-----cout key[5]-----
ctor: 0
MapValue: 0

-------runs here means, does't crash-------
dtor: 0
dtor: 2
dtor: 1

Ми бачимо, що: idName[5]викликати конструкцію map {5, MapValue(0)}для вставки в idName.

Але якщо ви викликаєте функцію-член до idName[5], тоді програма аварійно завершує роботу:

cout<<"-------create map<int, MapValue>-------"<<endl;

map<int, MapValue> idName{{1, MapValue(1)}, {2, MapValue(2)}};


idName[5].toString();  // get crash here.


cout<<"------- runs here means, doesn't crash-------"<<endl;

він не повинен розбиватися, тому що на карті має бути якась інша помилка
isti_spl

0

Будь ласка, подивіться виняток out_of_range: http://www.cplusplus.com/reference/stdexcept/out_of_range/

це те, що викине map :: at і map :: operator [], якщо ключ не існує. Ви можете зрозуміти це так само, як векторний приклад у посиланні.

Ви також можете використовувати: http://www.cplusplus.com/reference/map/map/find/

І порівняйте з map :: end


4
ні, лише map :: at throws, map :: operator [] створює новий тип_значення, якщо ключ не існує
galka
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.