Search code examples
c++post-incrementpostfix-operator

prefix operator behaviour in c++ when used multiple times in a statement


I am not able to understand prefix operator behaviour in scenario when it is used multiple times in a statement .
Here is an example code to illustrate my problem

#include<iostream>
using namespace std;

int main()
{   int a=2,adup=2;
    int b = (++a) * (++a);
    cout<<endl<<"square of "<<a<<" is "<<b<<endl;//i get 16
    int c = (++adup) * (++adup) * (++adup);
    cout<<endl<<"adup is "<<adup<<" and c is "<<c<<endl;// i get 80
    return 0;
}

Save above file as code.cpp and run 'gcc code.cpp -lstdc++' to verify.
It seems that in first case 2 was incremented twice then b = 4x4
But in second case I was hoping 5x5x5 on the lines of above but we ge 4x4x5 . How can that be explained ?
Thanks.

BTW , I found that postfix operator seems logical . it simply updates value and uses it next time variable is used even when in same statement .

After reading answers my conclusion is - Can it be said that using pre or post operation on same variable more than once in a statement will be undefined behaviour regardless of anything on LHS of expression ?


Solution

  • Earlier iterations of C++ (and C for that matter) had the concept of sequence points, where it was guaranteed all previous "things" (like the i++ side effect of evaluating that expression) would have completed.

    This was replaced at some point with more tightly described "sequencing" along the lines of:

    • if A is sequenced before B, A will be fully done before B starts.
    • if A is sequenced after B, A will be not start until B is fully done.
    • if A and B are indeterminately sequenced, one will complete fully before the other starts, but you won't necessarily know which one went first.
    • if A and B are unsequenced, either may start first, and they may even overlap.

    From C++20, [intro.execution], point 10 applies to your code:

    Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

    That means that the individual bits of that full expression may happen in any order, and even overlap, resulting in differing results to what you may think is correct.

    In other words, if you want deterministic code, don't do that.


    And, despite your findings that the "postfix operator seems logical, it simply updates [the] value and uses it next time [the] variable is used, even when in same statement", that is actually incorrect.

    While that may happen in a particular case, the expression (a++) * (a++) is equally as non-determinstic as (++a) * (++a).


    If you want to guarantee the sequencing of your operations, you can use more explicit code like:

    // int b = (++a) * (++a);
    // with pre-increment immediately before EACH use of a:
       int b = (a + 1) * (a + 2); a += 2;
    // or:
       int b = ++a; b = ++a * b
    

    There are always ways to achieve the same effect with code that isn't subject to indeterminate results, in the same number of lines of code if you concern yourself with that sort of metric, albeit with two statements on a single line :-)