是索引一个新的地图元素,并有一些东西读取它分配给它未定义的行为,或只是未指定? [英] Is indexing a new map element and having something that reads it assigned to it undefined behaviour, or just unspecified?

查看:233
本文介绍了是索引一个新的地图元素,并有一些东西读取它分配给它未定义的行为,或只是未指定?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在回答此问题后,对于所讨论的代码是否是未定义的行为存在一个长时间的讨论。这里是代码:

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

首先,已经确定这至少是未指定的。结果基于赋值的哪一侧首先被评估而不同。在我的回答中,我沿着四个结果的情况,与哪些方面先评估和元素是否存在之前的每个因素。



还有一个简短的表单:

  (x = 0)=(x == 0)? 1:2; // starts 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) //根据SO定义:未定义的行为和序列点

回到原来,我打破了下面的相关函数调用更容易遵循:

  operator =(word_count.operator [](a word_count.count(a)== 0?1:2); 
^ insert element ^ ^读取相同的元素
|
指定给元素

如果 word_count [a] 不存在,它被认为它将被分配到两次,而没有之间的排序。我个人没有看到如果两个事情我认为是真的,如果这是可能发生如下:



  1. 诸如word_count [a] = 1之类的构造体展现出良好的效果,


这两个语句是否为真?最终,是实际上未定义的行为,如果是,为什么第二个语句工作(假设它)?如果第二个是假,我相信所有 myMap [i] ++; 在世界上将是错误的。



有用的链接:未定义的行为和序列点

解决方案

行为未指定,但未定义



注意,在表达式中:

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

标记为 ^ 内置赋值运算符,因为 std :: map / code>返回 size_t&



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


赋值运算符(=)和复合赋值运算符所有组右-剩下。 [..] 在所有情况下,赋值在右侧和左侧操作数的值
计算之后,以及赋值表达式
的值计算之前排序。
对于不确定顺序的函数调用,复合赋值的操作是
a单独计算。


这表示在内置作业中,例如:

  a = b 

首先对操作数进行求值(以未指定的顺序),然​​后执行赋值操作,最后执行整个赋值表达式的值计算。 / p>

考虑原始表达式:

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

由于上面引用的段落,对同一对象的分配: 运算符执行的赋值之后,总是会对 ^ a不存在的情况下,作为左手侧表达式的评估的一部分[



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


After answering this question, there was a long discussion over whether the code in question was undefined behaviour or not. Here's the code:

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

First of all, it was well-established that this was at least unspecified. The result differs based on which side of the assignment is evaluated first. In my answer, I followed through each of the four resulting cases, with factors of which side is evaluated first and whether the element exists prior to this.

There was a short form that came up as well:

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

I claimed it was more like this:

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

Eventually, I found an example that seemed to work for me:

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

Back to the original, I broke it down into relevant function calls to make it easier to follow:

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

If word_count["a"] does not exist, it was argued that it would be assigned to twice without a sequencing in between. I personally didn't see how that could happen if two things I thought were true actually were:

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

  2. Constructs such as word_count["a"] = 1 exhibit well-defined behaviour, even in the case that an element is inserted and then assigned to.

Are these two statements true? Ultimately, is that actually undefined behaviour, and if it is, why does the second statement work (assuming it does)? If the second is false, I believe all the myMap[i]++;s in the world would be ill-formed.

Helpful Link: Undefined Behavior and Sequence Points

解决方案

The behavior is unspecified, but not undefined.

Notice, that in the expression:

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

The assignment operator marked with ^ is the built-in assignment operator, because std::map's operator [] returns a size_t&.

Per Paragraph 5.17/1 of the C++11 Standard on the built-in assignment operator(s):

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.

This means that in a built-in assignment such as:

a = b

First the operands are evaluated (in unspecified order), then the assignment is performed, and finally the value computation of the whole assignment expression is performed.

Considering the original expression:

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

Because of the paragraph quoted above, in no case there are two unsequenced assignments to the same object: the assignment marked with ^ will always be sequenced after the assignment performed by operator [] (as part of the evaluation of the left hand side expression) in case the key "a" is not present in the map.

However, the expression will have a different outcome based on which side of the assignment is evaluated first. Thus, the behavior is unspecified, but not undefined.

这篇关于是索引一个新的地图元素,并有一些东西读取它分配给它未定义的行为,或只是未指定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆