lastbreath
lastbreath

Reputation: 412

Operator Overloading behaves differently for classes and primtives

The following code when compiled and run using g++ outputs 22.

#include <iostream>

int main(){
    int a = 5;
    int c = ++a + ++a + ++a;
    std::cout << c << std::endl;
    return 0;
}

Floats also evaluate to the same value.

Whereas the following integer wrapper class outputs 24

#include <iostream>

class Int{
public:
    int data;
    
    Int( int value ) : data(value){}
    
    Int& operator++(){
       ++data;
       return *this;
    }
    
    Int operator+( const Int& b ){
        return Int( data + b.data );
    }
    
};

int main(){
    Int a = 5;
    Int c = ++a + ++a + ++a;
    std::cout << c.data << std::endl;
    return 0;
}

I am unable to understand why is there a difference in the outputs.

Could someone explain me in detail whats going on here?

Apart from this when both codes are compiled using clang the first code outputs 21 while the second code outputs 22.

PS : I know i shouldn't be using such an expression but my question is why are classes behaving differently than primitive types. Shouldn't they both parse to the same syntax tree and get evaluated in the same order. Even though the behaviour is undefined but for the same compiler, shouldn't they both behave in a similar manner

Upvotes: 0

Views: 165

Answers (1)

Jack Lilhammers
Jack Lilhammers

Reputation: 1247

Both int c = ++a + ++a + ++a; and Int c = ++a + ++a + ++a; result in undefined behavior.
You should avoid coding like that.

See https://en.cppreference.com/w/cpp/language/operator_incdec#Example,

and see the Undefined behaviour section of cppreference.com's Order of evaluation page:

Undefined behavior

  1. If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined.

    i = ++i + 2;       // undefined behavior until C++11
    i = i++ + 2;       // undefined behavior until C++17
    f(i = -2, i = -2); // undefined behavior until C++17
    f(++i, ++i);       // undefined behavior until C++17, unspecified after C++17
    i = ++i + i++;     // undefined behavior
    
  2. If a side effect on a scalar object is unsequenced relative to a value computation using the value of the same scalar object, the behavior is undefined.

    cout << i << i++; // undefined behavior until C++17
    a[i] = i++;       // undefined behavior until C++17
    n = ++i + i;      // undefined behavior
    

Here you can run your code with different compilers
Evaluation order on Visual C++
Evaluation order on Zapcc and GCC

Spoiler: Visual C++ behaves in the same way for primitive types and classes

On rextester you can try also Clang and GCC, but I can't add these links below the others without the editor telling me that there is some non-formatted code (which there isn't)
Evaluation order on Clang
Evaluation order on GCC

Upvotes: 4

Related Questions