Карты STL инициализируют примитивные типы при вставке? - PullRequest
43 голосов
/ 03 февраля 2009

У меня есть std::map, как это:

map<wstring,int> Scores;

Хранит имена игроков и результаты. Когда кто-то получает очки, я просто делаю:

Scores[wstrPlayerName]++;

Если на карте нет элемента с ключом wstrPlayerName, он создаст его, но инициализируется ли он нулем или нулем до приращения или он не определен?

Должен ли я проверять, существует ли элемент каждый раз перед увеличением?

Мне просто интересно, потому что я думал, что вещи примитивного типа всегда неопределенны при создании.

Если я напишу что-то вроде:

int i;
i++;

Компилятор предупреждает меня, что я не определен, и когда я запускаю программу, она обычно не равна нулю.

Ответы [ 4 ]

62 голосов
/ 03 февраля 2009

оператор [] выглядит так:

Value& map<Key, Value>::operator[](const Key& key);

Если вы вызовете его с помощью ключа , которого еще нет на карте, он по умолчанию создаст новый экземпляр Значение , поместит его на карту под ключом Вы прошли и вернули ссылку на него. В этом случае у вас есть:

map<wstring,int> Scores;
Scores[wstrPlayerName]++;

Здесь значение равно int , а целые числа построены по умолчанию как 0, как если бы вы инициализировали их с помощью int () . Другие типы примитивов инициализируются аналогично ( например , double () , long () , bool () и т. Д.).

В конце ваш код помещает новую пару (wstrPlayerName, 0) в карту, затем возвращает ссылку на int, который вы затем увеличиваете. Таким образом, нет необходимости проверять, существует ли элемент, если вы хотите, чтобы все начиналось с 0.

11 голосов
/ 03 февраля 2009

По умолчанию будет создан новый экземпляр value. Для целых чисел конструкцией по умолчанию является 0, так что это работает как задумано.

5 голосов
/ 03 февраля 2009

Вы не должны проверять, существует ли элемент, прежде чем увеличивать его. Оператор [] делает именно то, что вам нужно, как уже говорили другие.

Но что, если значение по умолчанию не будет работать для вас? В вашем случае лучший способ узнать, существует ли элемент, - это попытаться вставить его. Функция-член insert для std::map возвращает std::pair<iterator, bool>. Независимо от того, была ли вставка успешной или неудачной, первый элемент пары будет указывать на нужный объект (либо новый, либо уже существующий). Затем вы можете изменить его значение по своему усмотрению.

1 голос
/ 03 февраля 2009

Проверьте правила для инициализации.

См. Раздел 4.9.5 Инициализация C ++ Prog Lang или C ++ std book. В зависимости от того, является ли ваша переменная локальной, статической, пользовательской или постоянной, может произойти инициализация по умолчанию.

В вашем случае int называется POD (Обычный старый тип данных). Любая переменная POD auto (созданная в куче / локальной переменной) не инициализируется по умолчанию. Следовательно, для вас «я» выше не будет иметь значение ноль.

Всегда делайте привычку инициализировать POD, когда определено в куче. Вы даже можете использовать int () для инициализации значения.

...