From mboxrd@z Thu Jan 1 00:00:00 1970 From: "E. Robert Tisdale" To: egcs@egcs.cygnus.com Subject: Named Return Value Extension Proposal Date: Mon, 22 Mar 1999 13:10:00 -0000 Message-id: <36F6B101.2441947C@netwood.net> X-SW-Source: 1999-03/msg00728.html My egcs-2.90.29 980515 (egcs-1.0.3 release) compiler does not always elide copy constructors as permitted by the ANSI C++ standard so I propose an extension to the C++ language similar to named return values which the C++ programmer can use to help the compiler identify names which reference the return value. The following test program illustrates the problem: ---------------------------------------------------------------------- // test.cc #include class X { // a dynamic array class // representation int* p; // pointer to a huge array int n; // length of the huge array public: // constructors explicit X(int k): // explicit constructor definition p(new int[k]), n(k) { } X(const X& x); // copy constructor declaration ~X(void) { // destructor definition if (p) delete [] p; } // functions int length(void) const { return n; } // operators const int& operator [](int j) const { return p[j]; } int& operator [](int j) { return p[j]; } }; X::X(const X& x): // copy constructor definition p(new int[x.n]), n(x.n) { cerr << "The copy constructor was called!" << endl; for (int j = 0; j < n; j++) // copy the array p[j] = x.p[j]; } // user defined functions #define __return__ inline X f0(int n) { cerr << "The copy constructor may be called for f0(int)." << endl; return X(n); } inline X f1(int n) { X __return__ x(n); for (int j = 0; j < n; j++) // Modify x. x[j] = j; cerr << "The copy constructor may be called for f1(int)." << endl; return x ; } inline X f2(int n) return x(n) { for (int j = 0; j < n; j++) // Modify x. x[j] = j; } inline X g0(X x) { cerr << "The copy constructor may be called for g0(X)." << endl; return x; } inline X g1(const X& x) { cerr << "The copy constructor must be called for g1(const X&)." << endl; return x; } int main () { cerr << endl << "The copy constructor may be called for X x0 = f0(32);" << endl; X x0 = f0(32); cerr << endl << "The copy constructor may be called for X x1 = f1(32);" << endl; X x1 = f1(32); cerr << endl << "The copy constructor may be called for X x2 = f2(32);" << endl; X x2 = f2(32); cerr << endl << "The copy constructor may be called for X y0 = g0(f0(32));" << endl; X y0 = g0(f0(32)); cerr << endl << "The copy constructor may be called for X y1 = g1(x1);" << endl; X y1 = g1(x1); cerr << endl << "The copy constructor must be called for X z0 = y0;" << endl; X z0 = y0; return 0; } ---------------------------------------------------------------------- I compiled and ran the `test' program as follows: ---------------------------------------------------------------------- $ uname -rms Linux 2.0.36 i686 $ g++ --version egcs-2.90.29 980515 (egcs-1.0.3 release) $ g++ -O2 -felide-constructors -o test test.cc ./test The copy constructor may be called for X x0 = f0(32); The copy constructor may be called for f0(int). The copy constructor may be called for X x1 = f1(32); The copy constructor may be called for f1(int). The copy constructor was called! The copy constructor may be called for X x2 = f2(32); The copy constructor may be called for X y0 = g0(f0(32)); The copy constructor may be called for f0(int). The copy constructor may be called for g0(X). The copy constructor was called! The copy constructor may be called for X y1 = g1(x1); The copy constructor must be called for g1(const X&). The copy constructor was called! The copy constructor must be called for X z0 = y0; The copy constructor was called! $ ---------------------------------------------------------------------- Function X f2(int) illustrates the named return value extension as currently supported by my egcs compiler. See the GCC manual at http://egcs.cygnus.com/onlinedocs/gcc_5.html#SEC102 The current extension is very old now and it seems unlikely to me that it will ever be adopted as part of the ANSI C++ standard. It solves the problem that the egcs compiler has with function X f1(int) but the function definition is entirely incompatible with ANSI C++ and it cannot solve the problem that the compiler has with function X g0(X). Of course, the current named value extension must be retained for backward compatibility but I propose a simple extension which permits the C++ programmer to insert the `return' keyword between the type and the name in a declaration to identify the name as a reference to the return value as shown below: ---------------------------------------------------------------------- inline X f(int n) { X return x(n); // x is a reference to the return value. // Call the X(n) constructor to initialize it. for (int j = 0; j < n; j++) // Modify x. x[j] = j; return x; // Don't call the copy constructor! // Don't call the destructor for x! } inline X g(X return x) { // x is a reference to the return value. for (int j = 0; j < n; j++) // Modify x. x[j] = j; return x; // Don't call the copy constructor! // Don't call the destructor for x! } ---------------------------------------------------------------------- The constructor which would normally be called to initialize a temporary argument for g(X) would initialize the return value instead even if the the return value is not a temporary: ---------------------------------------------------------------------- int main () { X x(n); X y = g(x); // Don't create any temporary values. // Call the copy constructor // to initialize y from x directly // then pass a pointer to y // as the return value for g(X). return 0; } ---------------------------------------------------------------------- The portable application programmer can insert the `__return__' macro instead of the `return' keyword in declarations and prepend #define __return__ return for compilers which do support the proposed extension or #define __return__ for compilers which do not support the proposed extension. E. Robert Tisdale From mboxrd@z Thu Jan 1 00:00:00 1970 From: "E. Robert Tisdale" To: egcs@egcs.cygnus.com Subject: Named Return Value Extension Proposal Date: Wed, 31 Mar 1999 23:46:00 -0000 Message-ID: <36F6B101.2441947C@netwood.net> X-SW-Source: 1999-03n/msg00733.html Message-ID: <19990331234600.Ltkd6Zo6DHNQB_7R3jf0WJAdIDk_l0a-8ZmXyEp4FRI@z> My egcs-2.90.29 980515 (egcs-1.0.3 release) compiler does not always elide copy constructors as permitted by the ANSI C++ standard so I propose an extension to the C++ language similar to named return values which the C++ programmer can use to help the compiler identify names which reference the return value. The following test program illustrates the problem: ---------------------------------------------------------------------- // test.cc #include class X { // a dynamic array class // representation int* p; // pointer to a huge array int n; // length of the huge array public: // constructors explicit X(int k): // explicit constructor definition p(new int[k]), n(k) { } X(const X& x); // copy constructor declaration ~X(void) { // destructor definition if (p) delete [] p; } // functions int length(void) const { return n; } // operators const int& operator [](int j) const { return p[j]; } int& operator [](int j) { return p[j]; } }; X::X(const X& x): // copy constructor definition p(new int[x.n]), n(x.n) { cerr << "The copy constructor was called!" << endl; for (int j = 0; j < n; j++) // copy the array p[j] = x.p[j]; } // user defined functions #define __return__ inline X f0(int n) { cerr << "The copy constructor may be called for f0(int)." << endl; return X(n); } inline X f1(int n) { X __return__ x(n); for (int j = 0; j < n; j++) // Modify x. x[j] = j; cerr << "The copy constructor may be called for f1(int)." << endl; return x ; } inline X f2(int n) return x(n) { for (int j = 0; j < n; j++) // Modify x. x[j] = j; } inline X g0(X x) { cerr << "The copy constructor may be called for g0(X)." << endl; return x; } inline X g1(const X& x) { cerr << "The copy constructor must be called for g1(const X&)." << endl; return x; } int main () { cerr << endl << "The copy constructor may be called for X x0 = f0(32);" << endl; X x0 = f0(32); cerr << endl << "The copy constructor may be called for X x1 = f1(32);" << endl; X x1 = f1(32); cerr << endl << "The copy constructor may be called for X x2 = f2(32);" << endl; X x2 = f2(32); cerr << endl << "The copy constructor may be called for X y0 = g0(f0(32));" << endl; X y0 = g0(f0(32)); cerr << endl << "The copy constructor may be called for X y1 = g1(x1);" << endl; X y1 = g1(x1); cerr << endl << "The copy constructor must be called for X z0 = y0;" << endl; X z0 = y0; return 0; } ---------------------------------------------------------------------- I compiled and ran the `test' program as follows: ---------------------------------------------------------------------- $ uname -rms Linux 2.0.36 i686 $ g++ --version egcs-2.90.29 980515 (egcs-1.0.3 release) $ g++ -O2 -felide-constructors -o test test.cc ./test The copy constructor may be called for X x0 = f0(32); The copy constructor may be called for f0(int). The copy constructor may be called for X x1 = f1(32); The copy constructor may be called for f1(int). The copy constructor was called! The copy constructor may be called for X x2 = f2(32); The copy constructor may be called for X y0 = g0(f0(32)); The copy constructor may be called for f0(int). The copy constructor may be called for g0(X). The copy constructor was called! The copy constructor may be called for X y1 = g1(x1); The copy constructor must be called for g1(const X&). The copy constructor was called! The copy constructor must be called for X z0 = y0; The copy constructor was called! $ ---------------------------------------------------------------------- Function X f2(int) illustrates the named return value extension as currently supported by my egcs compiler. See the GCC manual at http://egcs.cygnus.com/onlinedocs/gcc_5.html#SEC102 The current extension is very old now and it seems unlikely to me that it will ever be adopted as part of the ANSI C++ standard. It solves the problem that the egcs compiler has with function X f1(int) but the function definition is entirely incompatible with ANSI C++ and it cannot solve the problem that the compiler has with function X g0(X). Of course, the current named value extension must be retained for backward compatibility but I propose a simple extension which permits the C++ programmer to insert the `return' keyword between the type and the name in a declaration to identify the name as a reference to the return value as shown below: ---------------------------------------------------------------------- inline X f(int n) { X return x(n); // x is a reference to the return value. // Call the X(n) constructor to initialize it. for (int j = 0; j < n; j++) // Modify x. x[j] = j; return x; // Don't call the copy constructor! // Don't call the destructor for x! } inline X g(X return x) { // x is a reference to the return value. for (int j = 0; j < n; j++) // Modify x. x[j] = j; return x; // Don't call the copy constructor! // Don't call the destructor for x! } ---------------------------------------------------------------------- The constructor which would normally be called to initialize a temporary argument for g(X) would initialize the return value instead even if the the return value is not a temporary: ---------------------------------------------------------------------- int main () { X x(n); X y = g(x); // Don't create any temporary values. // Call the copy constructor // to initialize y from x directly // then pass a pointer to y // as the return value for g(X). return 0; } ---------------------------------------------------------------------- The portable application programmer can insert the `__return__' macro instead of the `return' keyword in declarations and prepend #define __return__ return for compilers which do support the proposed extension or #define __return__ for compilers which do not support the proposed extension. E. Robert Tisdale