是否将地图大小作为值插入到地图未定义行为中?

NoS*_*tAl 4 c++ sequence-points unspecified-behavior

编辑:这个问题不应该被关闭,如果你查看答案,你会发现它们完全不同(旧问题没有提到 C++17)。

我正在阅读一篇 PVS博客文章,他们提到了以下错误。

(减少)

std::map<int,int> m;
m[7]=5;
auto val = 15;
if (!m.contains(val)){
    m[val] = m.size(); // bug here
}
Run Code Online (Sandbox Code Playgroud)

根据博客文章,这是错误的。我一直认为 operator [] 对 map 的调用是一个函数调用,所以 .size() 在 [] 之前被排序,因为函数充当序列点。

那么为什么这是一个错误呢?

注意:我知道从 C++11 开始就不存在序列点,但我使用它们是因为新的措辞对我来说更难理解。

bol*_*lov 5

前 C++17

§ 1.9 程序执行 [intro.execution](n3690 c++14 草案)

  1. 除非另有说明,否则单个运算符的操作数和单个表达式的子表达式的计算是无序的。

和 5.17 [expr.ass] 没有提到内置赋值操作数之间的任何排序。因此,对内置赋值运算符的两个操作数的计算=彼此之间是无序的。

m[val]并且m.size()可以以任何顺序进行评估(甚至可以重叠 - 交错 CPU 指令)。

考虑:

  • m[val] 具有修改地图大小(标量)的副作用

  • m.size()访问地图大小的值计算

§ 1.9 程序执行 [intro.execution](n3690 c++14 草案)

  1. [...] 如果对标量对象的副作用相对于 [...] 或使用相同标量对象的值的值计算是未排序的,则行为未定义。

所以是的,行为确实是未定义的。

C++17

§8.5.18 赋值和复合赋值运算符 [expr.ass](n4713 C++17 草案)

  1. 赋值运算符 (=) [...] 右操作数排在左操作数之前。

所以行为被定义了。m.size()之前会被评估m[val]