我会跳过标题
class X {
int i;
static int j;
public:
X(int ii = 1) : i(ii) {
j = i;
}
static int incr() {
return ++j;
}
static int f() {
return incr();
}
};
int _tmain(int argc, _TCHAR* argv[]) {
X x;
X* xp = &x;
cout << x.f() << xp->f() << X::f();
return 1;
}
此序列打印432,但在第一个视图中,可能会认为它将打印234。
如何确定函数调用的确切顺序?我错过了什么?
答案 0 :(得分:2)
流运营商只是一个运营商。 C++ allows operators to be defined a multitude of ways.您所看到的是&lt;&lt;字符串的运算符。你正在做的是同样的事情:
cout << "word1" << "word2" << "word3";
期望输出为:
"word1word2word3"
然而,评估顺序由&lt;&lt;&lt;&lt;运营商。通常上述内容相当于:
(((cout << "word1") << "word2") << "word3");
用函数替换字符串,你看到第一个被评估的字符串实际上是“word3”。这不是严格的情况,正如您通常会看到的那样。
(((cout << func1()) << func2()) << func3());
评估顺序为func3,func2,func1,打印顺序为func1,func2,func3的返回。
答案 1 :(得分:2)
§1.9.13
之前排序的是由单个执行的评估之间的不对称,传递,成对关系 线程(1.10),它引起这些评估中的部分顺序。给出任何两个评估A和B,如果 A在B之前被排序,然后A的执行应该在B的执行之前。如果A之前没有排序 B和B在A之前未被测序,然后A和B未被测序。 [注:执行无序 评估可以重叠。 -end note]当A或A时,评估A和B是不确定的 在A或B之前对B或B进行测序之前对其进行测序,但未指定哪一种。 [注意:不确定 有序的评估不能重叠,但可以先执行。 - 后注]
换句话说,调用函数的顺序是Undefined。这并不意味着“我们不知道”,它并不意味着“你无法解决” - 这意味着它被定义为没有定义;编译器和cpu可以任意顺序完成它们。
请考虑以下事项:
int a[3];
void f1() { a[0] = 1; }
void f2() { a[1] = 2; }
void f3() { a[2] = 3; }
int main() {
f1(), f2(), f3();
}
基本上,语言不要求在
之类的语句上进行排序std::cout << f1() << f2() << f3();
您的代码在函数调用之间没有序列点(http://en.wikipedia.org/wiki/Sequence_point);你可以弄清楚你的编译器生成的顺序,但它可能在不同的CPU或不同的优化级别上表现不同。
如果您有类似的可变函数调用,则需要手动提升或添加中断:
std::cout << f1();
std::cout << f2();
std::cout << f3();
或
auto a1 = f1();
auto a2 = f2();
auto a3 = f3();
std::cout << a1 << a2 << a3;
答案 2 :(得分:1)
本声明
cout << x.f() << xp->f() << X::f();
可以像
一样重写cout.operator <<( x.f() ).operator <<( xp->f() ).operator <<( X::f() );
未指定在此语句中用作参数的表达式的计算顺序。因此编译器可以例如从左到右或从右到左评估它们。因此,使用不同的编译器可以获得不同的结果。:)
要获得确定性结果,您应该重写语句
cout << x.f() << xp->f() << X::f();
例如
cout << x.f();
cout << xp->f();
coit << X::f();