jima@hplsla.HP.COM ( Jim Adcock) (04/13/88)
/* Actually, this might be an interesting example. The following program is about the same, except constructors and destructors make and destroy a value, and I'm using old i/o in order to make for easier decyphering of the resulting ..c intermediate file. The Million Dollar Question: what SHOULD the printf statement in main() print out ??? Explain your answer :-) */ #include <stdio.h> class foo { public: long value; foo () { printf("cons\n"); value = 1000000;} ~foo () { printf("dest\n"); value = 0;} }; foo bar() { foo a; return a; } main () { foo c = bar (); printf("c.value = %d\n",c.value); }
shopiro@alice.UUCP (04/16/88)
In article <6590034@hplsla.HP.COM>, jima@hplsla.UUCP writes: > > /* The Million Dollar Question: what SHOULD the printf statement > in main() print out ??? Explain your answer :-) > */ > > #include <stdio.h> > class foo > { > public: > long value; > foo () { printf("cons\n"); value = 1000000;} > ~foo () { printf("dest\n"); value = 0;} > }; > > foo bar() { foo a; return a; } > main () > { > foo c = bar (); // ***** > printf("c.value = %d\n",c.value); > } It should print c.value = 1000000 In the line marked with *****, c is initialized to be a copy of whatever bar() returns. In more detail, it is as if the programmer wrote class foo { public: long value; foo () { printf("cons\n"); value = 1000000;} ~foo () { printf("dest\n"); value = 0;} foo(const foo& f) : value(f.value) {} // this line supplied by compiler }; The perhaps unfamiliar syntax in the new line just copies the source value into the target value. The function foo::foo(const foo&) is called a ``copy-initializer.'' It is used whenever a new foo is to be a copy of an old one, that is, 1) a local foo is initialized from a foo { foo f = global_foo; // or ... = <foo_expression> ... } 2) a foo is passed to a function void foo_func(foo x); foo_func(f); // the local variable x in foo_func is initialized 3) a foo is returned from a function foo func_foo(); foo_func(func_foo()); // a local temp is initialized with the // result of func_foo() If a copy-initializer is not supplied by the programmer, the compiler generates the default version, which looks like the following for a class with arbitrary base classes and members. class D : B1, B2 ... { T1 m1; // m1 is a data member, T1 is a type T2 m2; ... }; D::D(const D& d) : B1(d.B1), B2(d.B2) ... m1(d.m1), m2(d.m2) ... {} Each initialization is the copy-initialization for the appropriate type. They are executed left to right. Of course, such copy-initialization is usually optimized to ``blast the bits from the source to the target''. If you leave the ``const'' specification out, you won't be able to copy a constant object. Following the same principles, the default assignment function is D& D::operator=(const D& d) { *(B1 *)this = (B1 &)d; *(B2 *)this = (B2 &)d; ... m1 = d.m1; m2 = d.m2; ... return *this; } It too is usually optimized to ``blast the bits.'' -- Jonathan Shopiro AT&T Bell Laboratories, Murray Hill, NJ 07974 research!shopiro (201) 582-4179
jima@hplsla.HP.COM ( Jim Adcock) (04/20/88)
| It should print | | c.value = 1000000 | | In the line marked with *****, c is initialized to be a copy of whatever | bar() returns. Okay, given that my local copy of the AT&T compiler (v1.2 ?) clearly generates intermediate C code that performs the destructor operation [setting c.value to zero] before the return of the function, thus printing: c.value = 0 is this a bug, or what ? How WOULD one generate C code for this operation -- returning the value of a structure, yet destroying the value of that structure before the function returns ?