[comp.lang.c++] What's the diff?

knutson@hsinchu.sw.mcc.com (Jim Knutson) (08/04/89)

What's the difference between the ++ operator overload functions in
these two examples?  The Lippman book (p. 197) prefers to define the
function type to return a reference to the class while the Pohl book
(p. 125) seems to prefer to return the class.  Both seem to work
equally well as both lvalue and rvalue.

class counter {
	int count;
public:
	counter() { count = 0; }
	counter(int c) { count = c; }
	counter& operator ++() { count++; return *this; }
	value() { return count; }
};

class counter {
	int count;
public:
	counter() { count = 0; }
	counter(int c) { count = c; }
	counter operator ++() { count++; return *this; }
	value() { return count; }
};

Jim Knutson
knutson@mcc.com
cs.utexas.edu!milano!knutson
-- 
Jim Knutson
knutson@mcc.com
cs.utexas.edu!milano!knutson

acw%illini@Sun.COM (Alex Wu [GPD] x6-6874) (08/05/89)

In article <2731@hsinchu.sw.mcc.com>, knutson@hsinchu.sw.mcc.com (Jim Knutson) writes:
> What's the difference between the ++ operator overload functions in
> these two examples?  The Lippman book (p. 197) prefers to define the
> function type to return a reference to the class while the Pohl book
> (p. 125) seems to prefer to return the class.  Both seem to work
> equally well as both lvalue and rvalue.
> 
> class counter {
> 	int count;
> public:
> 	counter() { count = 0; }
> 	counter(int c) { count = c; }
> 	counter& operator ++() { count++; return *this; }
> 	value() { return count; }
> };
> 
> class counter {
> 	int count;
> public:
> 	counter() { count = 0; }
> 	counter(int c) { count = c; }
> 	counter operator ++() { count++; return *this; }
> 	value() { return count; }
> };
> 

One difference I can think of is that the first class allows 
the cascade of "++" in this case, that is:

  counter i;
  (i++)++;
  cout << i.value() << '\n'; // gives 2

while the second one gives 1.
Alex Wu 
Sun Microsystems, Inc.
415-336-6874
acw@sun.com

dog@cbnewsl.ATT.COM (edward.n.schiebel) (08/07/89)

From article <119611@sun.Eng.Sun.COM>, by acw%illini@Sun.COM (Alex Wu [GPD] x6-6874):
>> these two examples?  The Lippman book (p. 197) prefers to define the
>> function type to return a reference to the class while the Pohl book
>> (p. 125) seems to prefer to return the class.  Both seem to work
>> equally well as both lvalue and rvalue.
>> 
...
> One difference I can think of is that the first class allows 
> the cascade of "++" in this case, that is:
> 
>   counter i;
>   (i++)++;

Also:
  By returning a reference, the result may be used as an lvalue.
  (i++) = something else;

  If used on the right hand side of an assignment i.e. j = i++, return
  by reference (almost) guarantees a copy of the object is not 
  created in the process.

	Ed Schiebel
	AT&T Bell Laboratories
	att!vilya!dog

dspoon@ncratl.Atlanta.NCR.COM (Dave Witherspoon) (08/07/89)

In article <2731@hsinchu.sw.mcc.com>, knutson@hsinchu.sw.mcc.com (Jim Knutson) writes:
> What's the difference between the ++ operator overload functions in
> these two examples?  The Lippman book (p. 197) prefers to define the
> function type to return a reference to the class while the Pohl book
> (p. 125) seems to prefer to return the class.  Both seem to work
> equally well as both lvalue and rvalue.
> 
> class counter {
> 	int count;
> public:
> 	counter() { count = 0; }
> 	counter(int c) { count = c; }
> 	counter& operator ++() { count++; return *this; }
> 	value() { return count; }
> };
> 
> class counter {
> 	int count;
> public:
> 	counter() { count = 0; }
> 	counter(int c) { count = c; }
> 	counter operator ++() { count++; return *this; }
> 	value() { return count; }
> };

I was recently puzzled by a very similar problem.  There is definitely
some reason to be cautious when returning values from operator overloads.
The reason to be careful is that if you return a reference to an object
allocated in the heap, then that object may never be destructed.  For
example, consider something like:

----------------------
class Frangis {
	private:
		int a;
	public:
		Frangis(int aa) {a=aa;}
		Frangis& operator+(Frangis &other_frangis);
};

Frangis& Frangis::operator+(Frangis &other_frangis)
{ return new Frangis(a + other_frangis.a);  }
-----------------------

The result is created in the heap and is copied (via operator=) into the
designated result variable you specify (or none).  When the program
terminates, any of these results from Frangis::operator+ will be left
hanging around in the heap.  Returning stack values from operator overloads 
has the benefit that all the space is returned automatically...the cost
is more stack space consumed and additional work in copying the
information.  

Returning a reference from an operator overload that affects "this
object" seems to be OK...that object already exists so no temporary
would be created for the return (methinks).  

To get a better understanding of how all this works, start with a very
simple class (like Frangis, which by the way is an excellent word to use
when you can't think of the right word) and overload its operator=
(i.e., create your own instead of using the default).  Also create one
overloaded operator function (e.g., "=") that returns a ref to a Frangis
and another (e.g., "-") that returns a Frangis.  Using cout's in the
Frangis constructor, destructor, oper=, oper+ and oper-, you should be
able to watch objects come and go.  If you can't account for all of them
when the program terminates, you know "something's up".

Hope this helps!
-------------------------------David Witherspoon-------------------------------
D.Witherspoon@Atlanta.NCR.COM         | "Dolphins find humans amusing, but 
NCR Retail Systems Development/Atlanta|  they don't want to talk to them."
MY OPINIONS...ALL MINE!!!             |               - David Byrne