Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ return reference variable in prefix overloading

I am confused when all the code I find shows returning a reference variable when overloading the prefix operator. I went through the parashift.com FAQ (http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.14) and it isn't clear, even though it says it WILL be clear when you read it. I adapted their example into a nonsensical, pointless little program to test.

#include<iostream>
using namespace std;

class Number {
   public:
      Number& operator++ ();    // prefix ++
      Number  operator++ (int); // postfix ++
      int value() { return value_; }
      void setValue(int value) { value_ = value; }
   private:
      int value_;
};

Number& Number::operator++ () {
   ++value_;
   return *this;
}

Number Number::operator++ (int unused) {
   Number temp;
   temp.setValue(value_);
   ++value_;
   return temp;
}

int main()
{
   Number someNum;
   someNum.setValue(20);
   cout << "someNum : " << someNum.value() << "\n";
   someNum++;
   ++someNum;
   cout << "someNum : " << someNum.value() << "\n";
   return 0;
}

The problem is, it works if I just declare it as a Number object as well like so:

#include<iostream>
using namespace std;

class Number {
   public:
      Number operator++ ();    // prefix ++
      Number  operator++ (int); // postfix ++
      int value() { return value_; }
      void setValue(int value) { value_ = value; }
   private:
      int value_;
};

Number Number::operator++ () {
   ++value_;
   return *this;
}

Number Number::operator++ (int unused) {
   Number temp;
   temp.setValue(value_);
   ++value_;
   return temp;
}

int main()
{
   Number someNum;
   someNum.setValue(20);
   cout << "someNum : " << someNum.value() << "\n";
   someNum++;
   ++someNum;
   cout << "someNum : " << someNum.value() << "\n";
   return 0;
}

I assume I simply need a better understanding of reference variables. Can anyone explain simply why the prefix operator SHOULD be coded as returning a reference variable?

like image 368
user985219 Avatar asked Oct 19 '25 23:10

user985219


2 Answers

The difference between :

Number& Number::operator++ () {
   ++value_;
   return *this;
}

and

Number Number::operator++ () {
   ++value_;
   return *this;
}

is that, when you use the first code, the following expression:

++(++(++someNum)); 

increments someNum THRICE. See the output here: http://ideone.com/y9UlY

However, when you use the second one, this

++(++(++someNum));

increments someNum just ONCE!! See the output here: http://ideone.com/eOLdj

It is because when you return the reference from operator++(), the second and third ++ invokes on the same object called someNum and therefore, it increments the same object, all the times. But when you return by value, the second and third ++ invokes on the temporary object which you returned from operator++(). Hence, the second and third call doesn't increment someNum, instead it increments the temporary objects which get destroyed at the end of the expression.

Now if the temporary objects get destroyed, why create then in the first place? After all, its pre-increment operator, which means the temporary and the original object will have the same value. So the good design decision is, return by reference when defining pre-increment operator, to avoid creating temporary, and improve performance.

like image 92
Nawaz Avatar answered Oct 22 '25 15:10

Nawaz


First, there's an efficiency issue. You are creating a new instance of the class in order to return it for no reason.

Second, there's the semantic issue. Your code invokes the empty constructor or the copy constructor to make the temporary and then destructs the temporary. If that has semantic meaning that's inappropriate, then the code doesn't really work, it just appears to.

Third, the code returns the wrong thing. Consider: ++foo.do_something();. With your code, we call 'do_something' on the temporary object. We wanted to call do_something() on the pre-incremented foo.

like image 36
David Schwartz Avatar answered Oct 22 '25 15:10

David Schwartz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!