Why does the following print bD aD aB aA aC aU
instead of aD aB aA aC bD aU
? In other words, why is b--
evaluated before --++a--++
?
#include <iostream>
using namespace std;
class A {
char c_;
public:
A(char c) : c_(c) {}
A& operator++() {
cout << c_ << "A ";
return *this;
}
A& operator++(int) {
cout << c_ << "B ";
return *this;
}
A& operator--() {
cout << c_ << "C ";
return *this;
}
A& operator--(int) {
cout << c_ << "D ";
return *this;
}
void operator+(A& b) {
cout << c_ << "U ";
}
};
int main()
{
A a('a'), b('b');
--++a-- ++ +b--; // the culprit
}
From what I gather, here's how the expression is parsed by the compiler:
--
++
a
--
++
+
b
--
;(--(++((a--)++))) + (b--)
;+
is left-to-right associative, but nonetheless the compiler may choose to evaluate the expression on the right (b--
) first.I'm assuming the compiler chooses to do it this way because it leads to better optimized code (less instructions). However, it's worth noting that I get the same result when compiling with /Od
(MSVC) and -O0
(GCC). This brings me to my question:
Since I was asked this on a test which should in principle be implementation/compiler-agnostic, is there something in the C++ standard that prescribes the above behavior, or is it truly unspecified? Can someone quote an excerpt from the standard which confirms either? Was it wrong to have such a question on the test?
1I realize the compiler doesn't really know about operator precedence or associativity, rather it cares only about the language grammar, but this should get the point across either way.
Order of evaluation refers to the operator precedence and associativity rules according to which mathematical expressions are evaluated.
Answer: Appendix A: Operator Precedence in Java. Java has well-defined rules for specifying the order in which the operators in an expression are evaluated when the expression has several operators. For example, multiplication and division have a higher precedence than addition and subtraction.
The order in which the operator are evaluated is called precedenceof operator.
Operators with the highest precedence will be evaluated first. Associativity of operators comes into the picture when the precedence of operators is the same and we need to decide which operator will be evaluated first.
The expression statement
--++a-- ++ +b--; // the culprit
can be represented the following way
at first like
( --++a-- ++ ) + ( b-- );
then like
( -- ( ++ ( ( a-- ) ++ ) ) ) + ( b-- );
and at last like
a.operator --( 0 ).operator ++( 0 ).operator ++().operator --().operator + ( b.operator --( 0 ) );
Here is a demonstrative program.
#include <iostream>
using namespace std;
#include <iostream>
using namespace std;
class A {
char c_;
public:
A(char c) : c_(c) {}
A& operator++() {
cout << c_ << "A ";
return *this;
}
A& operator++(int) {
cout << c_ << "B ";
return *this;
}
A& operator--() {
cout << c_ << "C ";
return *this;
}
A& operator--(int) {
cout << c_ << "D ";
return *this;
}
void operator+(A& b) {
cout << c_ << "U ";
}
};
int main()
{
A a('a'), b('b');
--++a-- ++ +b--; // the culprit
std::cout << std::endl;
a.operator --( 0 ).operator ++( 0 ).operator ++().operator --().operator + ( b.operator --( 0 ) );
return 0;
}
Its output is
bD aD aB aA aC aU
bD aD aB aA aC aU
You can imagine the last expression written in the functional form like a postfix expression of the form
postfix-expression ( expression-list )
where the postfix expression is
a.operator --( 0 ).operator ++( 0 ).operator ++().operator --().operator +
and the expression-list is
b.operator --( 0 )
In the C++ Standard (5.2.2 Function call) there is said that
8 [Note: The evaluations of the postfix expression and of the arguments are all unsequenced relative to one another. All side effects of argument evaluations are sequenced before the function is entered (see 1.9). —end note]
So it is implementation-defined whether at first the argument will be evaluated or the postfix expression. According to the showed output the compiler at first evaluates the argument and only then the postfix expression.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With