C++ 返回对象的函数调用和对该对象的方法调用之间是否存在序列点?
如果我写C++ 返回对象的函数调用和对该对象的方法调用之间是否存在序列点?,c++,sequence-points,unspecified-behavior,C++,Sequence Points,Unspecified Behavior,如果我写f(x)->g(args,…)我可以依赖f(x)之后的序列点来计算args,…?我可以从两个方面看待争论: §1.9.17“调用函数(无论函数是否为内联函数)时,在所有函数参数(如有)求值后有一个序列点在执行函数体中的任何表达式或语句之前发生。在复制返回值之后和执行函数外部的任何表达式之前,还有一个序列点。” 另一方面,对象指针隐式地是一个隐藏参数this,就好像我编写了g(f(x),args,…),这表明它类似于一个参数,因此未指定 ->操作符不是一个普通的二进制操作符,因为显然g
f(x)->g(args,…)
我可以依赖f(x)
之后的序列点来计算args,…
?我可以从两个方面看待争论:
- §1.9.17“调用函数(无论函数是否为内联函数)时,在所有函数参数(如有)求值后有一个序列点在执行函数体中的任何表达式或语句之前发生。在复制返回值之后和执行函数外部的任何表达式之前,还有一个序列点。”
- 另一方面,对象指针隐式地是一个隐藏参数
,就好像我编写了this
,这表明它类似于一个参数,因此未指定g(f(x),args,…)
->
操作符不是一个普通的二进制操作符,因为显然g(…)
不能在f(x)
之前求值,就像我写f(x)+g(…)
一样。我很惊讶我找不到关于它的具体陈述。注意,我认为你在标题中问了一个问题,在问题主体中又问了一个问题
其实并不矛盾。要评估您的功能,必须执行以下操作(不一定按此顺序)
- x被评估为(A)
- args被评估(B)
- 。。。被评估(C)
- f(x)称为(D)
- 复制f(x)的返回值(E)
- return->g(args,…)被调用(F)
*有趣的问题。如果g(args,…)是静态成员函数,会发生什么。在这种情况下,因为从f(x)返回的指针实际上没有传入,所以它可以提前排序吗?但是这是个独立的问题。< /P> < P>答案取决于你使用的C++标准版本(或者编译器正在使用)。 C++2003 5.2.2第8页说: 未指定参数的求值顺序。参数表达式求值的所有副作用在输入函数之前生效。未指定后缀表达式和参数表达式列表的求值顺序 这意味着在计算
f(x)
和args
之间不存在一个序列点
在C++ 2011中,序列点的整体概念已经被替换(参见),而现在的措辞只是一个注释:
[注:后缀表达式和参数表达式的求值都是相互不排序的。参数表达式求值的所有副作用都是在函数输入之前排序的(见1.9)。-结束注]
1.9p15表示
调用函数时(无论函数是否为内联函数),与任何参数表达式或与指定被调用函数的后缀表达式相关联的每个值计算和副作用都会在被调用函数体中的每个表达式或语句执行之前排序。[注:与不同参数表达式相关的值计算和副作用是不连续的。-结束注]
这表示表达式f(x)
和表达式args
在g
主体中的所有内容之前排序,但它们相对而言是不排序的,这与C++03规则相同,但措词不同
C++14的规则与C++11相同,但正如下面的注释所述,这些规则在C++17中发生了更改
C++2017 8.2.2[expr.call]p5说:
后缀表达式在表达式列表中的每个表达式和任何默认参数之前排序。参数的初始化,包括每个相关的值计算和副作用,相对于任何其他参数的初始化是不确定的
对于您的示例,这意味着以下步骤按顺序进行:
- 对
进行评估f
- 计算
,并初始化x
的参数f
- 计算函数调用
f(x)
进行评估f(x)->g
- 计算
和args
的其他参数,并初始化g
的参数(按未指定的顺序)g
- 最后,计算函数调用
f(x)->g(args,…)
->
是二进制运算符吗?如果忽略它的外观,它看起来像是一个一元运算符,返回指向某个类型的指针。@Yakk:它是一个一元运算符,但n元(排序)是T::g
,它将隐式this
与args
一起接受。问题是,在对成员函数g
的其余参数求值之前,是否对产生隐式this
的表达式进行了排序。这在C++17中发生了变化:“14)在函数调用表达式中,命名函数的表达式在每个参数表达式和每个默认参数之前排序。”因此,现在,f(x)将在参数之前求值。