被unordered_map的奇怪行为震惊了

Lao*_*Mao 10 c++ unordered-map c++14 c++17

这是一段非常简单的代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

如果地图不包含1,则分配m[1]=0; 否则m[1]=1.我在这里尝试了不同的gcc编译器.

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

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

Vla*_*cow 26

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

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

1赋值运算符(=)和复合赋值运算符从右到左分组.所有都需要一个可修改的左值作为左操作数,并返回一个左值操作数的左值.如果左操作数是位字段,则所有情况下的结果都是位字段.在所有情况下,赋值在右和左操作数的值计算之后,在赋值表达式的值计算之前排序.右操作数在左操作数之前排序..对于不确定序列的函数调用,复合赋值的操作是单个评估

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

1赋值运算符(=)和复合赋值运算符从右到左分组.所有都需要一个可修改的左值作为左操作数,并返回一个左值操作数的左值.如果左操作数是位字段,则所有情况下的结果都是位字段.在所有情况下,在右和左操作数的值计算之后,以及在赋值表达式的值计算之前,对赋值进行排序.对于不确定序列的函数调用,复合赋值的操作是单个评估.

正如您所看到的,C++ 2014 Standard的引用中没有粗体语句.

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

  • @taskinoor不,因为你评估左右两侧的顺序无关紧要.并且在评估双方之后总是进行实际分配.原始问题中的问题是在地图上调用operator []如果以前不存在,则使用默认值创建条目,这会更改右侧的find()调用的结果. (9认同)
  • 他们为什么会成为UB?RHS有哪些副作用,它们对LHS有依赖性? (2认同)