Just doing some sample test. I came across this.
Weird thing is, I remember doing this same snippet before, and I had no problem.
Did CERN mess up reality or what the mama?
The order of evaluation of subexpressions (beyond what is required by precedence rules and sequence point rules) is not defined. The expression cout << a.b() << a.a.b << endl may be evaluated as
1 2 3 4 5 6 7 8
//--------
//These evaluations may happen in any order.
auto subexpression_value4 = std::endl;
auto subexpression_value3 = a.a.b;
auto subexpression_value2 = a.b();
auto subexpression_value1 = std::cout;
//--------
subexpression_value1 << subexpression_value2 << subexpression_value3 << subexpression_value4;
Well then, how is it fair to put this as a question in an exam, asking you to determine the output of the snippet?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#include <iostream>
usingnamespace std;
class A {
public:
A() { a.a = a.b = 1; }
struct { int a,b; } a;
int b(void);
};
int A::b(void) { int x=a.a;a.a=a.b;a.b=x; return x; };
int main(void) {
A a;
a.a.a = 0;
a.b();
cout << a.b() << a.a.b << endl;
return 0;
}
When I parsed this, I came to the conclusion that "11" is the correct output...
Nevertheless, it is "10". Whoever wrote this snippet, did not bother with the order of evaluations, just compiled it and noted the output and decided the correct answer.
Well, why are you telling us? You should go tell whoever gave you that exam, so they can fix it.
But, nothing shocking about it. Programming teachers are usually pretty ignorant about the more obscure rules of a given language; C++ teachers doubly so. As the saying goes, those who can't do, teach.
What is the output of the following program?
#include <iostream>
usingnamespace std;
class A {
public:
A() { a[0] = 1; a[1] = 0; }
int a[2];
int b(void) { int x=a[0];a[0]=a[1];a[1]=x; return x; }
};
int main(void) {
A a;
a.b();
cout << a.b();
cout << a.a[1] << endl;
return 0;
}
1 - the program will cause a compilation error
2 - 00
3 - 11
4 - 10
This one uses an array instead of the struct, but the algorithm is the same.
But the big difference is that here, the 2 console outputs are put in 2 different cout statements...
And the correct answer is now actually predictable.
The output of the first snippet is also predictable (both options result in the output "11") in the current incarnation of the language (C++17).
The implementation has no choice in the matter; the order of evaluation is clearly specified.
16) Every overloaded operator obeys the sequencing rules of the built-in operator it overloads when called using operator notation.
19) In a shift operator expression E1<<E2 and E1>>E2, every value computation and side-effect of E1 is sequenced before every value computation and side effect of E2 http://en.cppreference.com/w/cpp/language/eval_order
So << is a sequence point now? Does that mean that x << a++ << a++ is no longer undefined?
They ought to just get it over with and define order of evaluation.
The concept of sequence points was subsumed by the sequenced-before rules in C++11.
The obsoleted C++98 sequence point rules were inaccurately/loosely specified even in C++98 (which was not concurrency-aware).
> Does that mean that x << a++ << a++ is no longer undefined?
Yes, no longer undefined after C++17.
More examples from cppreference (assumes that i is a scalar):
1 2 3 4 5 6 7 8 9 10 11
i = ++i + 2; // undefined behavior until C++11, well-defined in C++11
i = i++ + 2; // undefined behavior until C++17, well-defined in C++17
f(i = -2, i = -2); // undefined behavior until C++17, well-defined in C++17
cout << i << i++; // undefined behavior until C++17, well-defined in C++17
a[i] = i++; // undefined behavior until C++17, well-defined in C++17
f(++i, ++i); // undefined behavior until C++17, unspecified behaviour in C++17
i = ++i + i++; // undefined behavior even in C++17
n = ++i + i; // undefined behavior even in C++17