Назначение в C ++ происходит несмотря на исключение на правой стороне - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть некоторый (C ++ 14) код, который выглядит следующим образом:

map<int, set<string>> junk;
for (int id : GenerateIds()) {
    try {
        set<string> stuff = GetStuff();
        junk[id] = stuff;
    } catch (const StuffException& e) {
        ...
    }
}

Это работает. Иногда GetStuff() выдает исключение, которое работает нормально, потому что если это произойдет, я не хочу, чтобы значение в карте нежелательной почты.

Но сначала я написал это в цикле, который не работает:

junk[id] = GetStuff();

Точнее, даже когда GetStuff() выдает исключение, junk[id] создается (и ему присваивается пустой набор).

Это не то, что я ожидал: я ожидал, что они будут функционировать так же.

Есть ли здесь какой-то принцип C ++, который я неправильно понял?

Ответы [ 3 ]

0 голосов
/ 05 ноября 2018

Вы не понимаете, как operator[] работает на std::map.

Возвращает ссылку на сопоставленный элемент. Поэтому ваш код сначала вставляет элемент по умолчанию в эту позицию, а затем вызывает operator=, чтобы установить новое значение.

Чтобы все работало так, как вы ожидаете, вам нужно использовать std::map::insert (*):

junk.insert(std::make_pair(id, GetStuff()));

Предостережение : insert добавит значение, только если id еще не сопоставлено.

0 голосов
/ 05 ноября 2018

До C ++ 17 не было последовательности между левой и правой частью операторов присваивания.

Впервые в C ++ 17 было введено явное упорядочение (сначала вычисляется правая часть).

Это означает, что порядок оценки равен неопределен , что означает, что реализация должна выполнить оценку в том порядке, в котором она хочет, и в этом случае она сначала оценивает левую часть.

См. эту ссылку порядка оценки для более подробной информации (особенно пункт 20).

0 голосов
/ 05 ноября 2018

станд :: Карта :: оператор []

Возвращает ссылку на значение, сопоставленное ключу, эквивалентному ключ, выполняющий вставку, если такой ключ еще не существует.

junk[id] вызывает вышеупомянутую вставку и после того, как это уже произошло GetStuff() бросков. Обратите внимание, что в C ++ 14 порядок, в котором эти вещи происходят, определяется реализацией, поэтому с другим компилятором ваш junk[id] = GetStuff(); может не выполнить вставку, если GetStuff() throws.

...