c++ - 是在索引一个新的 map 元素并将读取它的东西分配给它未定义的行为,还是只是未指定的?

标签 c++ undefined-behavior operator-precedence sequence-points unspecified-behavior

回答后this question , 关于所讨论的代码是否为未定义行为的问题进行了长时间的讨论。这是代码:

std::map<string, size_t> word_count;
word_count["a"] = word_count.count("a") == 0 ? 1 : 2;

首先,众所周知,这至少是未指定的。结果因首先评估作业的哪一侧而异。在我的回答中,我遵循了四个结果案例中的每一个,首先评估哪一方的因素以及该元素是否在此之前存在。

还有一个简短的表格出现了:

(x = 0) = (x == 0) ? 1 : 2; //started as
(x = 0) = (y == "a") ? 1 : 2; //changed to

我声称它更像这样:

(x = 0, x) = (x == 0) ? 1 : 2; //comma sequences x, like [] should

最终,我找到了一个似乎对我有用的例子:

i = (++i,i++,i); //well-defined per SO:Undefined Behaviour and Sequence Points

回到最初,我将其分解为相关的函数调用,以便于理解:

operator=(word_count.operator[]("a"), word_count.count("a") == 0 ? 1 : 2);
   ^       inserts element^                        ^reads same element
   |
assigns to element

如果 word_count["a"] 不存在,有人认为它会被分配给 twice 而中间没有排序。如果我认为是真实的两件事实际上是:

  1. When a side is picked to be evaluated, the whole side has to be evaluated before the other side can start.

  2. 诸如 word_count["a"] = 1 的构造表现出明确定义的行为,即使在插入元素然后分配给的情况下也是如此。

这两个说法是真的吗?最终,这实际上是未定义的行为吗?如果是,为什么第二个语句有效(假设有效)?如果第二个为假,我相信世界上所有的 myMap[i]++; 都是病式的。

有用链接:Undefined behavior and sequence points

最佳答案

行为未指定,但并非未定义

注意,在表达式中:

word_count["a"] = word_count.count("a") == 0 ? 1 : 2;
//              ^

^标记的赋值运算符是内置赋值运算符,因为std::map运算符[ ] 返回一个 size_t&

根据 C++11 标准关于内置赋值运算符的第 5.17/1 段:

The assignment operator (=) and the compound assignment operators all group right-to-left. [..] 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.

这意味着在内置赋值中,例如:

a = b

首先对操作数进行求值(顺序不定),然后进行赋值,最后对整个赋值表达式进行值计算。

考虑原始表达式:

word_count["a"] = word_count.count("a") == 0 ? 1 : 2;
//              ^

由于上面引用的段落,在任何情况下都不会对同一对象有两个未排序的赋值:标记为 ^ 的赋值将始终在之后排序operator [] 执行的赋值(作为左侧表达式求值的一部分),以防键 "a" 不存在于 map 。

但是,根据首先评估赋值的哪一侧,表达式将有不同的结果。因此,行为是未指定的,但不是未定义的。

关于c++ - 是在索引一个新的 map 元素并将读取它的东西分配给它未定义的行为,还是只是未指定的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15865627/

相关文章:

c++ - 在 QMenuBar/QMenu 上捕获 keyPressEvent?

c++ - 如何使用gdb调试GUI程序

c++ - 为什么我可以在 begin() 上使用赋值运算符,即使它是一个右值?

java - MessageDigest.getInstance ("SHA") 返回什么特定的哈希算法?

c - sum+++i 是 C 中未定义的行为吗?

c - 为什么这些构造使用前后递增的未定义行为?

c++ - SSE,行主要与列主要性能问题

隐含点和括号的 Scala 优先级

SQL逻辑运算符优先级: And and Or

c - "a += a"是未定义的行为,例如 "i = i++"吗?