rjc@maui.cs.ucla.edu (03/17/89)
G++ 1.34.1 with GCC 1.34 Vax 8350, Ultrix V2.2-1 System #4 config.g++ vax I tried using named return values. It didn't seem to work as advertised. Is it broken, or was the advertisement wrong? >From ucla-cs!oberon!bloom-beacon!tut.cis.ohio-state.edu!YAHI.STANFORD.EDU!mdt Thu Mar 16 09:53:32 PST 1989 >[...] > >GNU C++ 1.34.1 also has three new experimental features. > >1. Named return values. Example: > >struct A { ... A (); A (A&); ... }; > >// old way >A foo () >{ > A tmp; // calls A() constructor > > ... things which modify `tmp' ... > return tmp; // calls A(A&) constructor >} > >// new way >A foo () return tmp; // calls A () constructor on entry >{ > ... things which modify `tmp' ... > return tmp; // call to A (A&) constructor not needed >} >[...] Following this description, we are told that tmp is not declared: bug.cc: ---------------------------------------------------------- /* test named return values * Rob Collins (rjc@cs.ucla.edu) */ struct A { int i; A(int x) { printf("A(%d)\n", x); i = x; }; A(A& x) { printf("A(A& x), x.i == %d\n", x.i); i = x.i; }; ~A(void) { printf("~A(%d)\n", i); }; void operator += (A& x) { printf("+=(%d, %d)\n", i, x.i); i += x.i; }; }; A foo (void) return tmp = 4; { printf("foo(void), tmp.i == %d\n", tmp.i); return tmp; } main() { A bar = 5; bar += foo(); printf("main(), bar.i == %d\n", bar.i); } ---------------------------------------------------------- Script started on Thu Mar 16 10:27:42 1989 % g++ -v bug.cc g++ version 1.34.1 /usr/local/lib/gcc-cpp -+ -v -undef -D__GNU__ -D__GNUG__ -Dvax -Dunix -D__vax__ -D__unix__ bug.cc /tmp/cc007922.cpp GNU CPP version 1.34 /usr/local/lib/gcc-c++ /tmp/cc007922.cpp -quiet -dumpbase bug.cc -noreg -version -o /tmp/cc007922.s GNU C++ version 1.34.1 (vax) compiled by GNU C version 1.34. In function foo (): bug.cc:15: `tmp' was not declared (first use this function) bug.cc:15: (Each undeclared identifier is reported only once bug.cc:15: for each function it appears in.) bug.cc:16: `tmp' was not declared (first use this function) % ^D script done on Thu Mar 16 10:27:51 1989 Adding a declaration of tmp inside the function foo results in successful compilation: bug.cc: ---------------------------------------------------------- /* test named return values * Rob Collins (rjc@cs.ucla.edu) */ struct A { int i; A(int x) { printf("A(%d)\n", x); i = x; }; A(A& x) { printf("A(A& x), x.i == %d\n", x.i); i = x.i; }; ~A(void) { printf("~A(%d)\n", i); }; void operator += (A& x) { printf("+=(%d, %d)\n", i, x.i); i += x.i; }; }; A foo (void) return tmp = 4; { A tmp = 1; printf("foo(void), tmp.i == %d\n", tmp.i); return tmp; } main() { A bar = 5; bar += foo(); printf("main(), bar.i == %d\n", bar.i); } ---------------------------------------------------------- Script started on Thu Mar 16 10:28:45 1989 % g++ -v bug.cc g++ version 1.34.1 /usr/local/lib/gcc-cpp -+ -v -undef -D__GNU__ -D__GNUG__ -Dvax -Dunix -D__vax__ -D__unix__ bug.cc /tmp/cc007930.cpp GNU CPP version 1.34 /usr/local/lib/gcc-c++ /tmp/cc007930.cpp -quiet -dumpbase bug.cc -noreg -version -o /tmp/cc007930.s GNU C++ version 1.34.1 (vax) compiled by GNU C version 1.34. gas /tmp/cc007930.s -o bug.o /usr/local/lib/gcc-ld++ -C /usr/local/lib/crt0+.o bug.o -lg++ /usr/local/lib/gcc-gnulib -lc % a.out A(5) A(1) foo(void), tmp.i == 1 A(A& x), x.i == 1 ~A(1) +=(5, 1) ~A(1) main(), bar.i == 6 ~A(6) % ^D script done on Thu Mar 16 10:29:12 1989 In foo(), the return value constructor is not called. In addition, tmp is copied on return from foo(). ------------------------------------------------------------------------------- rjc@cs.ucla.edu This is what happens when I sit on my keyboard: AISBDFAORI:KHGEDSYTFBFISKVDJ MN Next week: what happens when I throw my keyboard out the window!
rjc@maui.cs.ucla.edu (03/18/89)
rjc@cs.ucla.edu Vax 8350, Ultrix 2.2-1 System #4 G++ 1.34.1 (plus patched cplus-decl.c) Gcc 1.34 >[ Patch from Michael for cplus-decl.c ... ] > >yahi% >================================================================ >Here is the test program which now compiles: > >struct A { > int i; > A(int x) { printf("A(%d)\n", x); i = x; }; > A(A& x) { printf("A(A& x), x.i == %d\n", x.i); i = x.i; }; > ~A(void) { printf("~A(%d)\n", i); }; > void operator += (A& x) { printf("+=(%d, %d)\n", i, x.i); i += x.i; }; >}; > >A foo (void) return tmp = 4; >{ > printf("foo(void), tmp.i == %d\n", tmp.i); > return tmp; >} > >main() >{ > A bar = 5; > bar += foo(); > printf("main(), bar.i == %d\n", bar.i); >} >================================================================ >And here are the results: > >yahi% a.out >A(5) >A(4) <- ******** ~A() never called >foo(void), tmp.i == 4 >A(A& x), x.i == 4 <- ******** Shouldn't be called >+=(5, 4) >~A(4) >main(), bar.i == 9 >~A(9) >yahi% >================================================================ > >Michael Michael, Yes, the patch allows the test program to compile. Unfortunately, the code that is produced is badly broken. You can see in the above output that A(A&) is called on return from foo(). This is not supposed to happen with a named return (as I understand it). This is not too bad, just the same old inefficiency that we have been suffering with up to now. The *big* problem is that ~A() is not called for the `tmp' in foo(), but only for the copy produced by the call to A(A&) on return from foo(). I an not familiar with the interals of g++, so I cannot provide a fix. Thanks, rob collins (rjc@cs.ucla.edu) i n e w s i s b r a i n d a m a g e d ------------------------------------------------------------------------------- rjc@cs.ucla.edu This is what happens when I sit on my keyboard: AISBDFAORI:KHGEDSYTFBFISKVDJ MN Next week: what happens when I throw my keyboard out the window!
dl@ROCKY.OSWEGO.EDU (Doug Lea) (03/18/89)
I think Michael's documentation was wrong (or at least misleading). If you have a named return value, you should *only* return via `return' or by falling-off-the-edge. (Otherwise, in your example, it says to make tmp out of itself using A(A&), which is not very sensible.) See below. [Anyone wanting further rationale for this construct should see my recent comp.lang.c++ postings.] A few other notes about my experience with 1.34.1+ (1.34.1 plus Michael's 2 posted patches) on a vax750, 4.3BSD: The -felide-constructors switch seems buggy. All libg++ problems I've been able to diagnose when testing this switch appear due to the kind of local-variable-trashing behavior shown below. Note, however, that constructs both of the form `var a = fun()' and `var a(fun())' now, in 1.34.1, produce the same results (no temps!) with or without this switch. Using the -fsave-memoized switch also seems buggy. Several libg++ tests (test5, intList.cc) fail to compile with this switch. By the way, in the example, if you #include <stream.h>, you ought to use `cout.form(...)' (or `cout << form(...)') instead of `printf' to ensure proper flushing of output on program termination (on most machines, this apparently only matters if you are redirecting output). -Doug ------ file A.cc (a revision of rjc's example) #include <stream.h> struct A { int i; A(int x) { cout.form("A(%d)\n", x); i = x; }; A(A& x) { cout.form("A(A& x), x.i == %d\n", x.i); i = x.i; }; ~A(void) { cout.form("~A(%d)\n", i); }; void operator += (A& x) { cout.form("+=(%d, %d)\n", i, x.i); i += x.i; }; }; A foo () return tmp(4); // essentially equivalent to `tmp=4', // but explicitly use a constr. for clarity! { cout.form("foo(void), tmp.i == %d\n", tmp.i); return; // *not* `return tmp' } main() { A bar = 5; bar += foo(); cout.form("main(), bar.i == %d\n", bar.i); A baz = foo(); cout.form("main(), baz.i == %d\n", baz.i); A baz_con(foo()); cout.form("main(), baz_con.i == %d\n", baz_con.i); } -------- A correct compile/run without -felide-constructors R>g++ -g -O -finline-functions A.cc R>a.out A(5) A(4) foo(void), tmp.i == 4 +=(5, 4) ~A(4) main(), bar.i == 9 A(4) foo(void), tmp.i == 4 main(), baz.i == 4 A(4) foo(void), tmp.i == 4 main(), baz_con.i == 4 ~A(4) ~A(4) ~A(9) ----------- with -felide-constructors R>g++ -g -O -finline-functions -felide-constructors A.cc R>a.out A(5) A(4) foo(void), tmp.i == 4 +=(4, 4) # `bar' is trashed! main(), bar.i == 8 A(4) foo(void), tmp.i == 4 main(), baz.i == 4 A(4) foo(void), tmp.i == 4 main(), baz_con.i == 4 ~A(4) ~A(4) ~A(8)