索引一个新的map元素并且有一些东西读取它分配给它未定义的行为,或者只是未指定?

时间:2013-04-07 17:43:52

标签: 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"]不存在,则有人认为它将被分配两次,而两者之间没有排序。我个人没有看到如果我认为真实的两件事实际上是如何发生的那样:

  1. 当选择一个侧面进行评估时,必须在另一侧开始之前对整个侧面进行评估。

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

  3. 这两个陈述是真的吗?最终,实际上是未定义的行为,如果是,为什么第二个语句有效(假设确实如此)?如果第二个是假的,我相信世界上所有的myMap[i]++;都是不正确的。

    有用的链接:Undefined behavior and sequence points

2 个答案:

答案 0 :(得分:5)

行为未指定,但未定义

注意,在表达式中:

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

标有^的赋值运算符是内置赋值运算符,因为std::map的{​​{1}}返回operator []。< / p>

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

  

赋值运算符(=)和复合赋值运算符从右到左分组。 [..] 在所有情况下,赋值都在值之后排序   计算右和左操作数,并在赋值表达式的值计算之前。   对于不确定顺序的函数调用,复合赋值的操作是   一次评估。

这意味着在内置作业中,例如:

size_t&

首先评估操作数(以未指定的顺序),然​​后执行赋值,最后执行整个赋值表达式的值计算。

考虑原始表达:

a = b

由于上面引用的段落,在任何情况下都不会对同一个对象进行两次无序分配:标记为word_count["a"] = word_count.count("a") == 0 ? 1 : 2; // ^ 的作业将在执行分配后始终按排序如果地图中不存在关键字^,则按operator [] (作为左侧表达式评估的一部分)。

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

答案 1 :(得分:2)

未指明,但未定义。

word_count.operator[]("a")word_count.count("a")是函数调用。函数执行由标准保证不交错 - 首先在第二个之前完全排序或反过来。

具体定义可能因标准而异,在C ++ 11相关条款中为1.9 / 15:

  

调用函数中的每个评估(包括其他函数   在之前或之后没有特别排序的调用)   被调用函数体的执行是不确定的   关于被调用函数的执行顺序 9

     

9)换句话说,函数执行不会相互交错。

不确定顺序在1.9 / 13中定义:

  

当A为A时,评估A和B是不确定的   在B或B在A之前测序之前测序,但未指定   这

例如,评估:

word_count["a"] = word_count.count("a");

由三部分组成:

  1. 执行word_count.operator[]("a")
  2. 执行word_count.count("a")
  3. 分配
  4. <表示'在之前排序'。标准的引用部分保证1 < 22 < 1。在@Andy Prowl中引用的部分答案也显示了1 < 32 < 3。所以,只有两个选择:

    • 1 < 2 < 3
    • 2 < 1 < 3

    在这两种情况下,一切都完全排序,UB没有机会。