Naw*_*waz 27 c++ operator-precedence sequence-points
此代码取自此处的讨论.
someInstance.Fun(++k).Gun(10).Sun(k).Tun();
Run Code Online (Sandbox Code Playgroud)
这段代码是否定义明确?是否++k在kSun()之前评估过Fun ()?
如果k是用户定义的类型,而不是内置类型怎么办?以上函数调用顺序的方式与此不同:
eat(++k);drink(10);sleep(k);
Run Code Online (Sandbox Code Playgroud)
据我所知,在这两种情况下,每个函数调用后都存在一个序列点.如果是这样,为什么第一个案例也不能像第二个案例那样明确定义?
C++ ISO标准的1.9.17部分对序列点和功能评估进行了说明:
在调用函数时(无论函数是否为内联函数),在评估函数体中任何表达式或语句之前发生的所有函数参数(如果有) 之后,都会有 一个序列点.在复制返回值之后和执行函数外部的任何表达式之前,还有一个 序列点.
jal*_*alf 22
我想如果你确切地读到标准报价所说的内容,那么第一种情况就不会明确定义:
在调用函数时(无论函数是否为内联函数),在评估函数体中任何表达式或语句之前发生的所有函数参数(如果有)之后都有一个序列点
这告诉我们的不是"在函数的参数被评估之后唯一可能发生的事情就是实际的函数调用",而只是在参数的评估完成之后的某个时刻存在一个序列点,之前函数调用.
但如果你想象一个像这样的案例:
foo(X).bar(Y)
Run Code Online (Sandbox Code Playgroud)
这给我们的唯一保证是:
X在调用之前评估foo,和Y在调用之前进行评估bar.但是这样的订单仍然是可能的:
XYX与foo呼叫分离)fooY与bar呼叫分离)bar当然,我们也可以交换前两个项目,Y之前进行评估X.为什么不?该标准仅要求在函数体的第一个语句之前完全评估函数的参数,并且上述序列满足该要求.
这是我的解释,至少.它似乎没有说在参数评估和函数体之间不会发生任何其他事情 - 只是那两个被序列点分开.
Joh*_*itb 12
这取决于如何Sun定义.以下是明确定义的
struct A {
A &Fun(int);
A &Gun(int);
A &Sun(int&);
A &Tun();
};
void g() {
A someInstance;
int k = 0;
someInstance.Fun(++k).Gun(10).Sun(k).Tun();
}
Run Code Online (Sandbox Code Playgroud)
如果更改参数类型Sun为int,则它将变为未定义.让我们画一个版本的树int.
<eval body of Fun>
|
% // pre-call sequence point
|
{ S(increment, k) } <- E(++x)
|
E(Fun(++k).Gun(10))
|
.------+-----. .-- V(k)--%--<eval body of Sun>
/ \ /
E(Fun(++k).Gun(10).Sun(k))
|
.---------+---------.
/ \
E(Fun(++k).Gun(10).Sun(k).Tun())
|
% // full-expression sequence point
Run Code Online (Sandbox Code Playgroud)
可以看出,我们读取k(指定V(k))和k(在最顶部)没有被序列点分隔的副作用:在这个表达式中,相对于彼此的子表达式,没有序列点.最底部%表示全表达序列点.
Dav*_*har 10
这是未定义的行为,因为k的值在同一表达式中被修改和读取,没有插入序列点.看到这个问题的优秀长期答案.
1.9.17中的引用告诉您在调用函数体之前对所有函数参数进行求值,但没有说明在同一表达式中对不同函数调用的参数求值的相对顺序 - 没有保证"++ k Fun()在Sun()中的k之前进行评估".
eat(++k);drink(10);sleep(k);
Run Code Online (Sandbox Code Playgroud)
是不同的,因为它;是一个序列点,因此评估的顺序是明确定义的.
作为一个小测试,考虑:
#include <iostream>
struct X
{
const X& f(int n) const
{
std::cout << n << '\n';
return *this;
}
};
int main()
{
int n = 1;
X x;
x.f(++n).f(++n).f(++n).f(++n);
}
Run Code Online (Sandbox Code Playgroud)
我使用gcc 3.4.6运行它并且没有优化并得到:
5
4
3
2
Run Code Online (Sandbox Code Playgroud)
......用-O3 ......
2
3
4
5
Run Code Online (Sandbox Code Playgroud)
因此,无论是3.4.6的版本都有一个主要的错误(这有点难以置信),或者正如Philip Potter建议的那样,序列是不确定的.(GCC 4.1.1有/无-O3产生5,5,5,5.)
编辑 - 我在以下评论中的讨论摘要:
| 归档时间: |
|
| 查看次数: |
1758 次 |
| 最近记录: |