C ++中赋值语句的求值顺序 [英] Order of evaluation of assignment statement in C++

查看:177
本文介绍了C ++中赋值语句的求值顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  map< int,int> mp; 
printf(%d,mp.size());
mp [10] = mp.size();
printf(%d \\\
,mp [10]);

此代码产生的回答不是很直观:


0 1




我理解为什么会发生这种情况 - 引用 mp [10] 的基础值,同时创建上述值,然后才是右侧评估,使用新计算的 size()



这种行为是否在C ++标准的任何地方说明?或者是未定义的评估顺序?



结果是使用g ++ 5.2.1获得的。

解决方案

是的,这是由标准涵盖,它是未指定的行为。这种特殊情况在最近的C ++标准提案中有所介绍: N4228 :



它描述了这个问题,它描述了这个问题。如下:


表达式求值顺序是C ++
社区中一个定期讨论的主题。简言之,给定诸如 f(a,b,
c)
的表达式,子表达式 f,a,b,c 被评价为未被标准规定。如果这些子表达式中的任意两个碰巧修改相同的对象而没有中间的序列点,则程序的行为是未定义的。例如,表达式 f(i ++,i)其中i是一个
整数变量导致未定义的行为, v [i]
= i ++ <强>。即使行为未定义,评估表达式的结果仍然可以是任何人的客人。考虑
以下程序片段:

  #include< map& 

int main(){
std :: map< int,int> m;
m [0] = m.size(); //#1
}

地图对象在评估
标记为#1的语句? {{0,0}}或{{0,1}}?


我们知道,除非指定子表达式无效,这来自 C ++草稿11 standard section 1.9 程序执行




$ p
$ p
$ p
$ p

并且所有 5.17 分配和复合赋值运算符[expr.ass]说是:



< blockquote>

[...]在所有情况下,赋值在右值和左值操作数的值
计算之后,在赋值表达式的值计算之前。 。]


因此,本节不会明确评估的顺序,但我们知道这不是未定义的行为,因为 operator [] size()是函数调用,

:当调用函数时inline),与任何参数表达式或与指定被调用函数的后缀表达式相关联的每个值计算和副作用
是在被调用函数的主体中的每个表达式或语句执行之前被排序的
。 [注:价值
与不同参数表达式相关的计算和副作用不受影响。 -end note]
在调用函数(包括其他函数调用)中的每个评估,在被调用函数的正文执行之前或之后没有另外具体地
顺序,不确定地排序为
尊重被调用函数的执行
.9 [...]


在此问题中的 N4228 投标中的第二个有趣示例。 / p>

更新



看起来像是修改后的 N4228 由进化工作组在上一次WG21会议上接受,但论文( P0145R0 )尚不可用。所以这可能不再是C ++ 17中未指定的。


map<int, int> mp;
printf("%d ", mp.size());
mp[10]=mp.size();
printf("%d\n", mp[10]);

This code yields an answer that is not very intuitive:

0 1

I understand why it happens - the left side of the assignment returns reference to mp[10]'s underlying value and at the same time creates aforementioned value, and only then is the right side evaluated, using the newly computed size() of the map.

Is this behaviour stated anywhere in C++ standard? Or is the order of evaluation undefined?

Result was obtained using g++ 5.2.1.

解决方案

Yes, this is covered by the standard and it is unspecified behavior. This particular case is covered in a recent C++ standards proposal: N4228: Refining Expression Evaluation Order for Idiomatic C++ which seeks to refine the order of evaluation rules to make it well specified for certain cases.

It describes this problem as follows:

Expression evaluation order is a recurring discussion topic in the C++ community. In a nutshell, given an expression such as f(a, b, c), the order in which the sub-expressions f, a, b, c are evaluated is left unspecified by the standard. If any two of these sub-expressions happen to modify the same object without intervening sequence points, the behavior of the program is undefined. For instance, the expression f(i++, i) where i is an integer variable leads to undefined behavior , as does v[i] = i++. Even when the behavior is not undefined, the result of evaluating an expression can still be anybody’s guest. Consider the following program fragment:

#include <map>

int main() {
  std::map<int, int>  m;
  m[0] = m.size(); // #1
}

What should the map object m look like after evaluation of the statement marked #1? { {0, 0 } } or {{0, 1 } } ?

We know that unless specified the evaluations of sub-expressions are unsequenced, this is from the draft C++11 standard section 1.9 Program execution which says:

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.[...]

and all the section 5.17 Assignment and compound assignment operators [expr.ass] says is:

[...]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.[...]

So this section does not nail down the order of evaluation but we know this is not undefined behavior since both operator [] and size() are function calls and section 1.9 tells us(emphasis mine):

[...]When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function. [ Note: Value computations and side effects associated with different argument expressions are unsequenced. —end note ] Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.9[...]

Note, I cover the second interesting example from the N4228 proposal in this question here.

Update

It seems like a revised version of N4228 was accepted by the Evolution Working Group at the last WG21 meeting but the paper(P0145R0) is not yet available. So this could possibly no longer be unspecified in C++17.

这篇关于C ++中赋值语句的求值顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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