[comp.lang.c++] Correction to Re: Default constructor, unexpected call

brianl@wenti.Berkeley.EDU (Brian Lee) (08/02/90)

Many thanks to Brian Kennedy <bmk@dux.csc.ti.com> for kindly
pointing out that my example in Article 8944 really does produce
correct results.  This is just another example of a computer doing
what you told it to do instead of what you wanted it to do. :-)

In my example, the default constructors for superclasses are called
because my specification of the subclass copy constructor replaces
the default component-wise initialization that would have been
generated and by omission of explicit base initialization specifies
that the default constructors should be used.

For example, the classes

class X {
public:
    X()         { cout << "default X::X()\n"; }
    X(const X&) { cout << "copy X::X(const X&)\n"; }
};

class Y : public X {
public:
    Y()         { cout << "default Y::Y()\n"; }
//    Y(const Y&)       { cout << "copy Y::Y(const Y&)\n"; }
};

class Z : public Y {
public:
    Z()         { cout << "default Z::Z()\n"; }
    Z(const Z&) { cout << "copy Z::Z(const Z&)\n"; }
};

should really have been defined as

class X {
public:
    X()         { cout << "default X::X()\n"; }
    X(const X&) { cout << "copy X::X(const X&)\n"; }
};

class Y : public X {
public:
    Y()         { cout << "default Y::Y()\n"; }
//    Y(const Y& y) : X(y)       { cout << "copy Y::Y(const Y&)\n"; }
};

class Z : public Y {
public:
    Z()         		{ cout << "default Z::Z()\n"; }
    Z(const Z& z) : Y(z)	{ cout << "copy Z::Z(const Z&)\n"; }
};

The revised definitions work fine.

Sorry for any confusion this may have caused.

Brian Lee

leo@atcmp.nl (Leo Willems) (08/03/90)

From article <26655@pasteur.Berkeley.EDU>, by brianl@wenti.Berkeley.EDU (Brian Lee):
> Many thanks to Brian Kennedy <bmk@dux.csc.ti.com> for kindly
> pointing out that my example in Article 8944 really does produce
> correct results.  This is just another example of a computer doing
> what you told it to do instead of what you wanted it to do. :-)
> 

That may be, but your answer and the replay from Brain Kennedy have 
taken away the focus from my original problem.

Since everybody seems to be on the beach these days, here it is again.
My question is simple: why does the following program generate a 
call to the default constructor from class A for variable 'copd'?

(If this is not a bug in 2.1 (2.0 as well) try switching the
 declarations of a and b in class C; then A::A() is not called: if the 
previous one is NOT a bug then this one is!)


============

#include <stdio.h>

class A{
public:
	A() { ida = 0; puts("default constructor A()"); }
	A(int i) {ida = i; puts("constructor A(int)"); }
private:
	int ida;
};

class B{
public:
	B() { idb = 0; puts("default constructor B()"); }
	B(B& b) { idb = b.idb; puts("copy constructor B(B&)"); }
private:
	int idb;
};

class C{
public:
	C(){ puts("default constructor C()");}
protected:
	A a;	//switch these: bug(?) gone 
	B b;    // if not a bug: A::A() gone!!!!
};

main()
{
	puts(" first a 'default' constructor:");
	C defd;

	puts("\n now the copy constructor: ");

	C copd(defd);	//suspicious A::A() class here
}

========
Thanks in advance

Leo

dsa@dlogics.COM (David Angulo) (08/08/90)

In article <643@atcmpe.atcmp.nl>, leo@atcmp.nl (Leo  Willems) writes:
> My question is simple: why does the following program generate a 
> call to the default constructor from class A for variable 'copd'?
> 
> (If this is not a bug in 2.1 (2.0 as well) try switching the
>  declarations of a and b in class C; then A::A() is not called: if the 
> previous one is NOT a bug then this one is!)
> 
> 
> ============
> 
> #include <stdio.h>
> 
> class A{
> public:
> 	A() { ida = 0; puts("default constructor A()"); }
> 	A(int i) {ida = i; puts("constructor A(int)"); }
> private:
> 	int ida;
> };
> 
> class B{
> public:
> 	B() { idb = 0; puts("default constructor B()"); }
> 	B(B& b) { idb = b.idb; puts("copy constructor B(B&)"); }
> private:
> 	int idb;
> };
> 
> class C{
> public:
> 	C(){ puts("default constructor C()");}
> protected:
> 	A a;	//switch these: bug(?) gone 
> 	B b;    // if not a bug: A::A() gone!!!!
> };
> 
> main()
> {
> 	puts(" first a 'default' constructor:");
> 	C defd;
> 
> 	puts("\n now the copy constructor: ");
> 
> 	C copd(defd);	//suspicious A::A() class here
               ^^^^
       Well, I don't know how this compiled because you don't have
       anything other than a default constructor for class C.  This
       shouldn't have compiled!

> }
> 












I hate this stupid program









This is really stupid












Who wrote this junk?




-- 
David S. Angulo                  (312) 266-3134
Datalogics                       Internet: dsa@dlogics.com
441 W. Huron                     UUCP: ..!uunet!dlogics!dsa
Chicago, Il. 60610               FAX: (312) 266-4473

mat@mole-end.UUCP (Mark A Terribile) (08/09/90)

> > My question is simple: why does the following program generate a 
> > call to the default constructor from class A for variable 'copd'?


  [ real query about something that might be a real bug, ending with ]


> > class C{
> > public:
> > 	C(){ puts("default constructor C()");}
> > protected:
> > 	A a;	//switch these: bug(?) gone 
> > 	B b;    // if not a bug: A::A() gone!!!!
> > };
> >  . . .
> > 	C copd(defd);	//suspicious A::A() class here
>                ^^^^
>        Well, I don't know how this compiled because you don't have
>        anything other than a default constructor for class C.  This
>        shouldn't have compiled!



Except that copy constructors can be created by the compiler automatically,
and any investigation into this matter should take them into account by
declaring them private or else by declaring them public and providing them,
appropriately studded with probes.


It should compile (as far as I can see) and it did.  Not to say that there
might not be some interesting and subtle problems with it; I haven't got
that compiler (which I presume to be cfront) handy, else I would check.  If
the original author would check out the copy constructors, I would like to
hear of the results.


[ A bunch of blank lines ]
 

> I hate this stupid program


And the Net should care?


If you hate it, why bother to reply?  Why bother to repost the whole thing?
And if you are going to flame, please be right.  Otherwise people like me
will feel free to jump down your throat.


	``And them's that don't like me can leave me alone.''


[ Another bunch of blank lines ]
 

> This is really stupid


Well, it's pretty clear that SOMETHING is at least a little stupid; I don't
think that it's the original posting, however.  There's something subtle
going on in there.


[ Yet another bunch of blank lines ]


> Who wrote this junk?


His name was on it, as I recall.  I don't know that I can endorse the
appellation `junk' for HIS work.


> -- 
> David S. Angulo                  (312) 266-3134
> Datalogics                       Internet: dsa@dlogics.com
> 441 W. Huron                     UUCP: ..!uunet!dlogics!dsa
> Chicago, Il. 60610               FAX: (312) 266-4473


I hope that the author of the remarks was not the individual whose name
appears in the signature; this wouldn't be the first case of a pirated account.
The infamous Case of the Impersonation of Elizabeth Bimmler comes to mind.



	``And then some deranged cat-molester begins posting about the
	role of contraception in the development of the ball-point pen.''
						--The Hitch-Hiker's Guide
						  To The Net
-- 

 (This man's opinions are his own.)
 From mole-end				Mark Terribile

bmk@osage.csc.ti.com (Brian M Kennedy) (08/15/90)

In article <615@dlogics.COM>, dsa@dlogics.COM (David Angulo) writes:
=>
=>In article <643@atcmpe.atcmp.nl>, leo@atcmp.nl (Leo  Willems) writes:
=>=> My question is simple: why does the following program generate a 
=>=> call to the default constructor from class A for variable 'copd'?
=>=> 
=>=> (If this is not a bug in 2.1 (2.0 as well) try switching the
=>=>  declarations of a and b in class C; then A::A() is not called: if the 
=>=> previous one is NOT a bug then this one is!)
=>=> 
=>=> #include <stdio.h>
=>=> 
=>=> class A{
=>=> public:
=>=> 	A() { ida = 0; puts("default constructor A()"); }
=>=> 	A(int i) {ida = i; puts("constructor A(int)"); }
=>=> private:
=>=> 	int ida;
=>=> };
=>=> 
=>=> class B{
=>=> public:
=>=> 	B() { idb = 0; puts("default constructor B()"); }
=>=> 	B(B& b) { idb = b.idb; puts("copy constructor B(B&)"); }
=>=> private:
=>=> 	int idb;
=>=> };
=>=> 
=>=> class C{
=>=> public:
=>=> 	C(){ puts("default constructor C()");}
=>=> protected:
=>=> 	A a;	//switch these: bug(?) gone 
=>=> 	B b;    // if not a bug: A::A() gone!!!!
=>=> };
=>=> 
=>=> main()
=>=> {
=>=> 	puts(" first a 'default' constructor:");
=>=> 	C defd;
=>=> 
=>=> 	puts("\n now the copy constructor: ");
=>=> 
=>=> 	C copd(defd);	//suspicious A::A() class here
=>               ^^^^
=>       Well, I don't know how this compiled because you don't have
=>       anything other than a default constructor for class C.  This
=>       shouldn't have compiled!
=>
=>=> }
=>=> 

In response to David, this should compile.  A copy constructor is implicitly
defined for every class unless a copy constructor is explicitly defined.
In this case, the following declaration in class C is implicit:

      C (C&);

(Note, it is not C (const C&) because C has a member B which has a copy 
constructor that does not accept a const argument. E&S p295)


In response to Leo's question, which I will rephrase "Why does the implicit
copy constructor generated for class C call the default constructor for class
A?  Is this a bug?":

There are many statements in E&S which somewhat imply how an implicit copy
constructor is implemented -- however, it is never spelled out.  I believe
Leo is assuming (a perfectly reasonable assumption) that it is implemented as:

      C (C& i) :a(i.a), b(i.b) {}

where b(i.b) calls the user-defined copy constructor, and a(i.a) calls the
implicit constructor

      A (A& i) :ida(i.ida) {}

A look at the cfront 2.00.01 generated C shows that the implicit copy 
constructor is defined using the implicit memberwise assignment (or, at
least, achieves a similar result):

      C (C& i) :a(), b(i.b) {<perform "bitwise" copy of i.a to a>}


Is it a compiler bug?  Only if the C++ language requires compilers to 
define copy constructors a certain way.  I do not believe E&S does so.
It does define exactly how copy constructors should be DECLARED and 
when they should be DEFINED, but it only hints at how it should be
DEFINED.  In fact, E&S (p295) hints that a compiler could do "bitwise" 
copying in the implicit copy constructors.  Perhaps the ANSI spec should
be more clear about this.


So, as with any language or architecture spec, if the language definition
does not define something, you should not assume that it is one way -- 
Murphy's law will see to it that you get burned ;-)

In all but the simplest of the classes that I write, I always define both
a default constructor and a copy constructor.  Then I always know how it 
is defined (besides, it is next to trivial to write).

Hope that helps.

Disclaimer:  I have made educated guesses -- only the ATT'ers can say for
             sure what cfront is trying to do here and whether or not it
             is a bug (i.e. unintended behavior).

---------------------------------
Brian M. Kennedy <bmk@csc.ti.com>
Computer Systems Laboratory
Computer Science Center
Texas Instruments Incorporated

rfg@NCD.COM (Ron Guilmette) (08/16/90)

In article <1990Aug14.190925.19166@csc.ti.com> bmk@osage.csc.ti.com (Brian M Kennedy) writes:
<...
<In response to Leo's question, which I will rephrase "Why does the implicit
<copy constructor generated for class C call the default constructor for class
<A?  Is this a bug?":
<
<There are many statements in E&S which somewhat imply how an implicit copy
<constructor is implemented -- however, it is never spelled out.  I believe
<Leo is assuming (a perfectly reasonable assumption) that it is implemented as:
<
<      C (C& i) :a(i.a), b(i.b) {}
<
<where b(i.b) calls the user-defined copy constructor, and a(i.a) calls the
<implicit constructor
<
<      A (A& i) :ida(i.ida) {}
<
<A look at the cfront 2.00.01 generated C shows that the implicit copy 
<constructor is defined using the implicit memberwise assignment (or, at
<least, achieves a similar result):
<
<      C (C& i) :a(), b(i.b) {<perform "bitwise" copy of i.a to a>}
<
<
<Is it a compiler bug?  Only if the C++ language requires compilers to 
<define copy constructors a certain way.  I do not believe E&S does so.
<It does define exactly how copy constructors should be DECLARED and 
<when they should be DEFINED, but it only hints at how it should be
<DEFINED.  In fact, E&S (p295) hints that a compiler could do "bitwise" 
<copying in the implicit copy constructors.  Perhaps the ANSI spec should
<be more clear about this.

No.  The ANSI standard should *DEFINITELY* be more clear about this!

Note that the same lack of specificity exists also for the definitions
of implicitly supplied (i.e. compiler generated) default constructors
and assignment operators.

-- 

// Ron Guilmette  -  C++ Entomologist
// Internet: rfg@ncd.com      uucp: ...uunet!lupine!rfg
// Motto:  If it sticks, force it.  If it breaks, it needed replacing anyway.

jimad@microsoft.UUCP (Jim ADCOCK) (08/18/90)

In article <1990Aug14.190925.19166@csc.ti.com> bmk@osage.csc.ti.com (Brian M Kennedy) writes:
>Is it a compiler bug?  Only if the C++ language requires compilers to 
>define copy constructors a certain way.  I do not believe E&S does so.
>It does define exactly how copy constructors should be DECLARED and 
>when they should be DEFINED, but it only hints at how it should be
>DEFINED.  In fact, E&S (p295) hints that a compiler could do "bitwise" 
>copying in the implicit copy constructors.  Perhaps the ANSI spec should
>be more clear about this.

Hm, I thought it was clear that E&S pg 295 was saying that a smart compiler
could recognize when the results of a generated copy constructor would
be identical to a bitwise copy, and just do the bitwise copy using an
intrinsic.

In any case, the small text annotation "hints" such as this one, do
not constitute part of the text the ANSI-fication effort is working from.