对 unordered_map 的奇怪行为感到震惊

Shocked by the strange behavior of 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;
}

如果map不包含1,则赋值m[1]=0;否则 m[1]=1。我用不同的 gcc 编译器 here.

试过了

gcc5.2总是输出1,gcc7.1总是输出0。

为什么如此不同?它不应该总是0吗?我无法理解这种行为。写这样的逻辑最安全的方法是什么?

结果取决于编译器是否支持 C++ 2017。

根据 C++ 2017 标准(5.18 赋值和复合赋值运算符)

1 The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand. The result in all cases is a bit-field if the left operand is a bit-field. In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression The right operand is sequenced before the left operand.. With respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation

另一方面,根据 C++ 2014 标准(5.18 赋值和复合赋值运算符)

1 The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand. The result in all cases is a bit-field if the left operand is a bit-field. In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression. With respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation.

如您所见,C++ 2014 标准的引用中没有粗体字。

所以你不应该依赖左右操作数的评估顺序。