views:

156

answers:

3

I'm wanting to make sure I understand pass-by-value vs pass-by-reference properly. In particular, I'm looking at the prefix/postfix versions of the increment ++ operator for an object.

Let's suppose we have the following class X:

class X{
private:
    int i;
public:
 X(){i=0;}
 X& operator ++ (){ ++i; return *this; } //prefix increment

 X operator ++ (int unused){ //postfix increment
  X ret(*this);
  i++;
  return ret;
 }

 operator int(){ return i; } //int cast
};

First of all, have I implemented the prefix/postfix increment operators properly?

Second, how memory-efficient is the postfix operator, compared to the prefix operator? Specifically how many X object copies are created when each version of the operator is used?

An explanation of exactly what happens with return-by-reference vs return-by-value might help me understand.


Edit: For example, with the following code...

X a;
X b=a++;

...are a and b now aliases?

+2  A: 

This is a correct implementation. It is typical that a postfix operator will be worse on performance because you have to create another copy before doing the increment (and this is why I've gotten in the habit of always using prefix unless I need something else).

With return-by-reference, you're returning an l-value reference to the current object. The compiler would typically implement this by returning the address of the current object. This means that returning the object is as simple as returning a number.

However, with return-by-value, a copy must be done. This means there's more information to copy over during the return (instead of just an address) as well as a copy constructor to call. This is where your performance hit comes in.

The efficiency of your implementation looks on-par with typical implementations.

EDIT: With regards to your addendum, no, they are not aliases. You have created two separate objects. When you return by value (and when you created a new object from within the postfix increment operator) this new object is placed in a distinct memory location.

However, in the following code, a and b are aliases:

 int a = 0;
 int& b = ++a;

b is an address which references a.

Shirik
Perfect - thanks.
Cam
Correct in general, modulo possible Return Value Optimization (http://en.wikipedia.org/wiki/Return_value_optimization).
Nikolai N Fetissov
+2  A: 

Your operators are implemented correctly.

In the prefix operator, no copies of X are made.

In the postfix operator, one copy is made for ret, and potentially another copy is made when returning from the function, but all compilers will elide this copy.

Peter Alexander
+4  A: 

It is more idiomatic to call the prefix increment of the object itself in the postfix increment:

X operator++(int)
{
    X copy(*this);
    operator++();   // or alternatively, ++(*this);
    return copy;
}

The logic of incrementing an X object is thus contained in the prefix version.

FredOverflow
Yep, this frees me from posting the same correction. `+1` from me.
sbi