[comp.std.c++] Default copy constructor not making a copy

klein@blsouth.UUCP (Michael Klein) (02/26/91)

Can someone explain why the two classes defined below exhibit different
behavior?  The class without the default copy constructor does not make
a copy of the *this argument for the + operator.  There is a related
comment in Ellis & Stroustrup (12.6.1): "Had no copy constructor been
declared...all would have happened exactly as before because a copy
constructor would have been generated.  Again, a good compiler would
eliminate the use of the generated copy constructor."  I'm not convinced
that this statement applies in this case.  Any enlightenment on this
subject would be welcome.  I'm using ATT C++ 2.0 on a Sparc.


#include <iostream.h>
#include <iomanip.h>

class NoCopy {
public:
  int x;
  NoCopy (int a) { x = a; };
  NoCopy &operator +=(int a) { x += a; return *this; };
  NoCopy  operator + (int a) { return NoCopy(*this) += a; };
};

class Copy {
public:
  int x;
  Copy(const Copy &c) : x(c.x) {};
  Copy (int a) { x = a; };
  Copy &operator =(int a) { x = a; return *this; };
  Copy &operator +=(int a) { x += a; return *this; };
  Copy  operator + (int a) { return Copy(*this) += a; };
};

void main()
{
  NoCopy xNo(1), xNo2(-1);
  Copy xYes(2), xYes2(-2);
  cout << "No=" << xNo.x << " Yes=" << xYes.x << endl;
  cout << "No2=" << xNo2.x << " Yes=" << xYes2.x << endl;
  xNo2 = xNo + 2;
  xYes2 = xYes + 2;
  cout << "No=" << xNo.x << " Yes=" << xYes.x << endl;
  cout << "No2=" << xNo2.x << " Yes=" << xYes2.x << endl;
}

Output of the program:
No=1 Yes=2
No2=-1 Yes=-2
No=3 Yes=2
No2=3 Yes=4

lijewski@theory.tn.cornell.edu (Mike Lijewski) (02/27/91)

In article <253@blsouth.UUCP> klein@blsouth.UUCP (Michael Klein) writes:
>
>Can someone explain why the two classes defined below exhibit different
>behavior?  The class without the default copy constructor does not make
>a copy of the *this argument for the + operator.  There is a related
>comment in Ellis & Stroustrup (12.6.1): "Had no copy constructor been
>declared...all would have happened exactly as before because a copy
>constructor would have been generated.  Again, a good compiler would
>eliminate the use of the generated copy constructor."  I'm not convinced
>that this statement applies in this case.  Any enlightenment on this
>subject would be welcome.  I'm using ATT C++ 2.0 on a Sparc.
>
>
>#include <iostream.h>
>#include <iomanip.h>
>
>class NoCopy {
>public:
>  int x;
>  NoCopy (int a) { x = a; };
>  NoCopy &operator +=(int a) { x += a; return *this; };
>  NoCopy  operator + (int a) { return NoCopy(*this) += a; };
>};

Replacing the line

   NoCopy  operator + (int a) { return NoCopy(*this) += a; };

with

   NoCopy  operator + (int a) { NoCopy tmp = *this; return tmp += a; };

you will get what you expected.  This could be taken to be a bug, but
I'm inclined to think that it's just another grey area in the
language which is best avoided.  No where in E&S is there any example
or text that I can find which states that one can explicitely call a
copy constructor which the compiler generates for you.  My
understanding is that if you make use of a construct which requires a
copy constructor, the "right thing" will be done, where the "right
thing" is a bitwise copy.

It is interesting to note that when I tried the original code with
g++, I got an error to the effect that the argument in
`NoCopy(*this)' is wrong - g++ was expecting an int since the only
constructor which had been defined was NoCopy::Nocopy(int).
Seemingly g++ doesn't allow one to explicitely call a copy
constructor which you haven't explicitely defined.  I would suggest
that this is the more correct behavior.  Certainly it is better than
silently allowing the construct and then doing the wrong thing.

>class Copy {
>public:
>  int x;
>  Copy(const Copy &c) : x(c.x) {};
>  Copy (int a) { x = a; };
>  Copy &operator =(int a) { x = a; return *this; };
>  Copy &operator +=(int a) { x += a; return *this; };
>  Copy  operator + (int a) { return Copy(*this) += a; };
>};
>
>void main()
>{
>  NoCopy xNo(1), xNo2(-1);
>  Copy xYes(2), xYes2(-2);
>  cout << "No=" << xNo.x << " Yes=" << xYes.x << endl;
>  cout << "No2=" << xNo2.x << " Yes=" << xYes2.x << endl;
>  xNo2 = xNo + 2;
>  xYes2 = xYes + 2;
>  cout << "No=" << xNo.x << " Yes=" << xYes.x << endl;
>  cout << "No2=" << xNo2.x << " Yes=" << xYes2.x << endl;
>}
>
>Output of the program:
>No=1 Yes=2
>No2=-1 Yes=-2
>No=3 Yes=2
>No2=3 Yes=4


-- 
Mike Lijewski  (H)607/272-0238 (W)607/254-8686
Cornell National Supercomputer Facility
ARPA: mjlx@eagle.cnsf.cornell.edu  BITNET: mjlx@cornellf.bitnet
SMAIL:  25 Renwick Heights Road, Ithaca, NY  14850