首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++中赋值语句的求值顺序

C++中赋值语句的求值顺序
EN

Stack Overflow用户
提问于 2015-11-08 20:54:19
回答 4查看 4.8K关注 0票数 18
代码语言:javascript
复制
map<int, int> mp;
printf("%d ", mp.size());
mp[10]=mp.size();
printf("%d\n", mp[10]);

这段代码产生了一个不太直观的答案:

0 1

我理解为什么会发生这种情况--赋值的左边返回对mp[10]的基础值的引用,同时创建上述值,然后使用映射的新计算的size()对右侧进行计算。

这种行为是否符合C++标准?或者是评估的顺序没有定义?

用g++ 5.2.1进行了结果分析。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-11-08 23:26:42

是的,这是标准所涵盖的,而且它是未指定的行为。这一特殊情况在最近的一项C++标准建议中涉及到:N4228:改进惯用C++的表达式求值顺序,该建议旨在细化评估规则的顺序,使其适合于某些情况。

报告对这一问题的描述如下:

表达式评估顺序是C++社区中反复出现的讨论主题。简单地说,给定一个表达式(如f(a,b,c) ),计算子表达式f、a、b、c的顺序未由标准指定。如果这些子表达式中的任何两个碰巧修改同一个对象而没有插入序列点,则程序的行为是未定义的。例如,表达式f(i++,i) (其中我是整数变量)导致未定义的行为,vi = i++也是如此。即使行为不是未定义的,计算表达式的结果仍然可以由任何人来猜测。考虑以下程序片段: #包括int (){ std::map m;m= m.size();// #1 } 在计算标记为#1的语句{{0,0}或{ {0,1}}之后,map对象m应该是什么样子?

我们知道,除非指定子表达式的计算没有排序,否则这来自起草C++11标准1.9 Program execution,其中说:

除注意到的情况外,对个别运算符的操作数和个别表达式的子表达式的计算均未排序。

5.17赋值和复合赋值操作符expr.ass说的全部内容是:

...In所有情况下,赋值是在计算右和左操作数的值之后,以及在计算赋值表达式的值之前.

因此,本节没有确定计算的顺序,但我们知道这不是未定义的行为,因为operator []size()都是函数调用,1.9部分告诉我们(强调我的):

...When调用函数(无论函数是否内联),与任何参数表达式关联的每一值计算和副作用,或与指定被调用函数的后缀表达式相关联的每个值计算和副作用,在执行被调用函数正文中的每个表达式或语句之前都会进行排序。注意:与不同参数表达式相关联的值计算和副作用是不按顺序排列的。-end注意在调用函数(包括其他函数调用)中,在被调用函数的主体执行之前或之后未进行特定排序的每个计算值,对于被调用函数.9的执行都是不确定的排序。

注意,我在问题这段来自“C++编程语言”第4版36.3.6节的代码是否具有定义良好的行为?中介绍了N4228提案中的第二个有趣的例子。

更新

N4228的修订版似乎是进化工作组在上次WG21会议上接受,但该论文(P0145R0)尚未面世。因此,这可能不再是C++17中未指定的。

更新2

p0145的第3版指定并更新了[expr.ass]p1

赋值运算符(=)和复合赋值运算符都是从右向左分组的.它们都需要一个可修改的lvalue作为它们的左操作数;它们的结果是一个指向左操作数的lvalue。如果左操作数是位字段,则所有情况下的结果都是位字段.在所有情况下,分配都是在计算右和左操作数的值之后,以及在分配表达式的值计算之前进行的。右操作数在左操作数之前被排序。.

票数 19
EN

Stack Overflow用户

发布于 2015-11-08 21:18:25

来自C++11标准(强调“地雷”):

5.17赋值和复合赋值算子 1赋值运算符(=)和复合赋值运算符均由右向左分组.它们都需要一个可修改的lvalue作为它们的左操作数,并返回一个引用左操作数的lvalue。如果左操作数是位字段,则所有情况下的结果都是位字段.在所有情况下,分配是在计算右和左操作数的值之后,以及在赋值表达式的值计算之前进行排序的。

该语言没有指定左操作数是先计算还是右操作数是先计算的。编译器可以自由选择首先计算任何一个操作数。由于代码的最终结果取决于操作数的计算顺序,所以我认为它是未指定的行为,而不是未定义的行为。

1.3.25未指定的行为 对于格式良好的程序构造和正确的数据,这取决于实现。

票数 8
EN

Stack Overflow用户

发布于 2015-11-08 21:02:00

我确信标准没有为表达式x = y;指定在C++标准中计算顺序xy的顺序(这就是为什么不能执行*p++ = *p++,例如,因为p++不是按照定义的顺序进行的)。

换句话说,要保证order x = y;按定义的顺序进行,您需要将其分解为两个序列点。

代码语言:javascript
复制
 T tmp = y;
 x = tmp;

(当然,在这种情况下,人们可能会假设编译器更喜欢在operator[]之前执行size(),因为它可以将值直接存储到operator[]的结果中,而不是将其保存在临时位置,以便在对operator[]进行评估之后将其存储起来--但我很确定编译器不需要按照这种顺序执行它)

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33598938

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档