[comp.lang.c++] Constructor called with reference to self?

tom@ssd.csd.harris.com (Tom Horsley) (11/02/90)

Given a class that looks like:

class someclass {
public:
   someclass(someclass& arg);
   ...
}

Is it ever possible with a correctly functioning C++ compiler for your
program to reach the body of the if statement in the following copy
constructor:

someclass::someclass(someclass& arg)
{
   if (this == &arg) {
      // Can I get here?
   }
}

In other words can a copy constructor ever be called with a reference to
self as its argument?

I hope the answer is 'NO' since all the C++ books emphasize that
constructors only get raw bits and it is their job to initialize those bits.
So if '*this' is raw bits and 'arg' is a reference to an already existing
class, how can they be located at the same point in memory?

I spent several hours last night determining that this is actually happening
in a Turbo C++ program I wrote in which I have overloaded a lot of
arithmetic operators and have written some complex expressions involving
these overloaded operators. When I modified my constructors to detect this
case and avoid clobbering the information it is about to copy, the program
started working flawlessly (it worked on two different g++ implementations
before I tried it on Turbo C++).

Does this look as much like a bug to everyone else as it does to me, or have
I possibly encountered one of those subtle gotcha's that always seem to
attract programmers who are just starting to use a new language?
--
======================================================================
domain: tahorsley@csd.harris.com       USMail: Tom Horsley
  uucp: ...!uunet!hcx1!tahorsley               511 Kingbird Circle
                                               Delray Beach, FL  33444
+==== Censorship is the only form of Obscenity ======================+
|     (Wait, I forgot government tobacco subsidies...)               |
+====================================================================+

jbuck@galileo.berkeley.edu (Joe Buck) (11/03/90)

In article <TOM.90Nov2072213@hcx2.ssd.csd.harris.com>, tom@ssd.csd.harris.com (Tom Horsley) writes:
|> Is it ever possible with a correctly functioning C++ compiler for your
|> program to reach the body of the if statement in the following copy
|> constructor:
|> 
|> someclass::someclass(someclass& arg)
|> {
|>    if (this == &arg) {
|>       // Can I get here?
|>    }
|> }
|> 
|> In other words can a copy constructor ever be called with a reference to
|> self as its argument?

What's probably happened is that your program has a memory allocation bug.
Specifically, you've deleted an object but you still have a pointer to
it lying around, so you're trying to use an object that you have deleted.
Neophytes always think they've found a compiler bug when this bites them.

|> I spent several hours last night determining that this is actually happening
|> in a Turbo C++ program I wrote in which I have overloaded a lot of
|> arithmetic operators and have written some complex expressions involving
|> these overloaded operators. When I modified my constructors to detect this
|> case and avoid clobbering the information it is about to copy, the program
|> started working flawlessly (it worked on two different g++ implementations
|> before I tried it on Turbo C++).

You either have a bug in your memory allocation somewhere that didn't bite
you under g++ for some reason, or there's a bug in one of the Turbo C++
classes that you are using.

--
Joe Buck
jbuck@galileo.berkeley.edu	 {uunet,ucbvax}!galileo.berkeley.edu!jbuck	

tom@ssd.csd.harris.com (Tom Horsley) (11/03/90)

>What's probably happened is that your program has a memory allocation bug.
>Specifically, you've deleted an object but you still have a pointer to
>it lying around, so you're trying to use an object that you have deleted.
>Neophytes always think they've found a compiler bug when this bites them.

Yep. I would agree that this is a very likely thing to happen except for the
fact that all my class instances are 'auto' storage class, I am not using
new or delete (to create classes) anywhere.

The more I look at it, the more it looks like Turbo C++ is re-using one of
the temps it created for evaluation of the expression (involving overloaded
operators) before the lifetime of that temp actually expired.
--
======================================================================
domain: tahorsley@csd.harris.com       USMail: Tom Horsley
  uucp: ...!uunet!hcx1!tahorsley               511 Kingbird Circle
                                               Delray Beach, FL  33444
+==== Censorship is the only form of Obscenity ======================+
|     (Wait, I forgot government tobacco subsidies...)               |
+====================================================================+

vaughan@mcc.com (Paul Vaughan) (11/04/90)

   From: tom@ssd.csd.harris.com (Tom Horsley)

   Given a class that looks like:

   class someclass {
   public:
      someclass(someclass& arg);
      ...
   }

   Is it ever possible with a correctly functioning C++ compiler for your
   program to reach the body of the if statement in the following copy
   constructor:

   someclass::someclass(someclass& arg)
   {
      if (this == &arg) {
	 // Can I get here?
      }
   }

Yes and No.  I agree with you that it generally shouldn't happen, but
here is a case where it can.

#include <stream.h>

class A {
public:
  A() {}
  A(A& a) { if( this == &a) cout << "copying myself\n"; }
};

main() {
  A* a1 = new A;
  delete a1;
  A* a2 = new A(*a1);          // <= using a dead object here
}

Both g++ and sun cfront 2.0 print "copying myself" on this one, but
that has more to do with the malloc/free package than anything else.
The various compilers differ in the details of when temporary objects
created as arguments in expressions get deleted.  This might account
for why it works differently under different compilers.  Also, note
that constructors don't exactly get raw bits--all members have been
constructed and the constructor initialization list has been run
before the constructor body is run.  But, basically, a copy
constructor should never find itself copying itself.

 Paul Vaughan, MCC CAD Program | ARPA: vaughan@mcc.com | Phone: [512] 338-3639
 Box 200195, Austin, TX 78720  | UUCP: ...!cs.utexas.edu!milano!cadillac!vaughan

BMS101@psuvm.psu.edu (11/09/90)

I A COMING IN IN THE MIDDLE OF THIS THREAD BUT IF IT HASN'T BEEN SAID ALREADY
TURBO C++ DOES HAVE MEMORY ALLOCATION BUGS THAT CAN BE CORRECTED BY CALLING
BORLAND AND D/L'ING  THEIR BUG FIXES.