Moi*_*ñas 105 c++ operator-precedence chaining
该程序的输出:
#include <iostream>
class c1
{
public:
c1& meth1(int* ar) {
std::cout << "method 1" << std::endl;
*ar = 1;
return *this;
}
void meth2(int ar)
{
std::cout << "method 2:"<< ar << std::endl;
}
};
int main()
{
c1 c;
int nu = 0;
c.meth1(&nu).meth2(nu);
}
Run Code Online (Sandbox Code Playgroud)
方法是:
method 1
method 2:0
Run Code Online (Sandbox Code Playgroud)
开始nu时为什么不是1 meth2()?
Lig*_*ica 64
因为评估订单未指定.
你看到nu在main被评估到0之前甚至meth1被调用.这是链接的问题.我建议不要这样做.
只需制作一个简单,清晰,易读,易于理解的程序:
int main()
{
c1 c;
int nu = 0;
c.meth1(&nu);
c.meth2(nu);
}
Run Code Online (Sandbox Code Playgroud)
Sme*_*eey 28
我认为关于评估顺序的标准草案的这一部分是相关的:
1.9程序执行
...
- 除非另有说明,否则对单个运算符的操作数和单个表达式的子表达式的评估是不确定的.在运算符的结果的值计算之前,对运算符的操作数的值计算进行排序.如果对标量对象的副作用相对于同一标量对象的另一个副作用或使用相同标量对象的值进行的值计算未被排序,并且它们不可能是并发的,则行为未定义
并且:
5.2.2函数调用
...
- [注意:后缀表达式和参数的评估都是相对于彼此的.在输入函数之前,参数评估的所有副作用都会被排序 - 结束注释]
因此,对于您的行c.meth1(&nu).meth2(nu);,请考虑最终调用的函数调用运算符在运算符中发生的情况meth2,因此我们清楚地看到后缀表达式和参数的细分nu:
operator()(c.meth1(&nu).meth2, nu);
Run Code Online (Sandbox Code Playgroud)
根据上面的函数调用规则,对最终函数调用的后缀表达式和参数(即后缀表达式c.meth1(&nu).meth2和nu)的评估相对于彼此是无序的.因此,相对于函数调用之前的参数评估,对标量对象上的后缀表达式的计算的副作用是未序的.通过上面的程序执行规则,这是未定义的行为.arnumeth2
换句话说,编译器不需要nu在meth2调用后评估调用的参数meth1- 可以自由地假设没有meth1影响nu评估的副作用.
上面生成的汇编代码在main函数中包含以下序列:
nu在堆栈上分配并初始化为0.ebx在我的情况下)收到值的副本nunu和c加载到参数寄存器中meth1 叫做nu在ebx寄存器被加载到参数寄存器meth2 叫做关键的是,在上面的步骤5中,编译器允许nu在函数调用中重用步骤2 的缓存值meth2.在这里,它忽略了可能nu通过调用meth1"未定义的行为" 而改变的可能性.
注意:此答案的实质内容已从原始形式发生变化.我最初的解释是在最终函数调用之前未对操作数计算进行排序的副作用是不正确的,因为它们是.问题在于操作数本身的计算是不确定的.
在1998 C++标准中,第5节,第4段
除非另有说明,否则单个运算符的操作数和单个表达式的子表达式的评估顺序以及副作用发生的顺序是未指定的.在前一个和下一个序列点之间,标量对象应通过表达式的计算最多修改其存储值一次.此外,只能访问先前值以确定要存储的值.对于完整表达式的子表达式的每个允许排序,应满足本段的要求; 否则行为未定义.
(我省略了对脚注#53的引用,这与此问题无关).
基本上,&nu必须在调用之前进行评估c1::meth1(),并且nu必须在调用之前进行评估c1::meth2().然而,有没有这个要求nu之前评估&nu(例如,它是允许的nu可以先进行计算,然后&nu,再c1::meth1()被称为-这可能是你的编译器做的).表达*ar = 1在c1::meth1()因此不能保证之前评估nu在main()进行评价时,以被传递给c1::meth2().
后来的C++标准(我目前在PC上没有使用的标准)具有基本相同的条款.
小智 6
我认为在编译时,在真正调用函数meth1和meth2之前,参数已经传递给它们.我的意思是当你使用"c.meth1(&nu).meth2(nu);" 值nu = 0已经传递给meth2,所以后者改变"nu"无关紧要.
你可以试试这个:
#include <iostream>
class c1
{
public:
c1& meth1(int* ar) {
std::cout << "method 1" << std::endl;
*ar = 1;
return *this;
}
void meth2(int* ar)
{
std::cout << "method 2:" << *ar << std::endl;
}
};
int main()
{
c1 c;
int nu = 0;
c.meth1(&nu).meth2(&nu);
getchar();
}
Run Code Online (Sandbox Code Playgroud)
它会得到你想要的答案
| 归档时间: |
|
| 查看次数: |
7411 次 |
| 最近记录: |