Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is '--++a-​- ++ +b--' evaluated in this order?

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:

  • Preprocessor tokenization: -- ++ a -- ++ + b --;
  • Operator precedence1: (--(++((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.

like image 894
Konstantin Avatar asked Apr 06 '17 18:04

Konstantin


People also ask

What is an evaluation order?

Order of evaluation refers to the operator precedence and associativity rules according to which mathematical expressions are evaluated.

What determines the order in which 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.

What is the order in which the operators are evaluated?

The order in which the operator are evaluated is called precedenceof operator.

Which operator is evaluated first?

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.


1 Answers

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.

like image 173
Vlad from Moscow Avatar answered Sep 23 '22 05:09

Vlad from Moscow