Потрясенный странным поведением unordered_map

Это очень простой фрагмент кода:

#include <cstdio>
#include <unordered_map>

int main() {  
    std::unordered_map<int, int> m;
    m[1] = m.find(1) == m.end() ? 0 : 1;
    printf("%d\n", m[1]);
    return 0;
}

Если карта не содержит 1, то присвойте m[1]=0; иначе m[1]=1. Я попробовал это с различными компиляторами gcc здесь.

gcc5.2 всегда выводит 1, gcc7.1 всегда выдает 0.

Почему это так отличается? Разве это не должно быть 0 всегда? Я не понимаю этого поведения. Какой самый безопасный способ написать такую ​​логику?

Ответ 1

Результат зависит от того, поддерживает ли компилятор С++ 2017.

В соответствии со стандартом С++ 2017 (5.18 Операторы присваивания и составного присваивания)

1 Оператор присваивания (=) и составные операторы присваивания все группы справа налево. Все требуют модификации lvalue как их левые операнд и возвращает lvalue, ссылаясь на левый операнд. Результат во всех случаях это бит-поле, если левый операнд является битовым полем. В целом случаев, присваивание упорядочивается после вычисления значения правый и левый операнды, а перед вычислением значения выражение присваивания Правильный операнд секвенирован перед левым операнд.. Что касается вызова функции с неопределенной последовательностью, работа составного присвоения - это единая оценка

С другой стороны, в соответствии со стандартом С++ 2014 (5.18 Назначение и составные операторы присваивания)

1 Оператор присваивания (=) и составные операторы присваивания все группы справа налево. Все требуют модификации lvalue как их левые операнд и возвращает lvalue, ссылаясь на левый операнд. Результат во всех случаях это бит-поле, если левый операнд является битовым полем. В целом случаев, присваивание упорядочивается после вычисления значения правый и левый операнды, а перед вычислением значения присваивание. Что касается неопределенно-секвенированного вызов функции, операция составного присвоения является одиночным оценка.

Как вы можете видеть, выражение, выделенное полужирным шрифтом, отсутствует в цитате из стандарта С++ 2014.

Таким образом, вы не должны полагаться на порядок оценки левого и правого операндов.