GNU C++ extends the function-definition syntax to allow you to specify a name for the result of a function outside the body of the definition, in C++ programs:
type functionname (args) return resultname; { ... body ... }
You can use this feature to avoid an extra constructor call when
a function result has a class type. For example, consider a function
m
, declared as `X v = m ();', whose result is of class
X
:
X m () { X b; b.a = 23; return b; }
Although m
appears to have no arguments, in fact it has one implicit
argument: the address of the return value. At invocation, the address
of enough space to hold v
is sent in as the implicit argument.
Then b
is constructed and its a
field is set to the value
23. Finally, a copy constructor (a constructor of the form `X(X&)')
is applied to b
, with the (implicit) return value location as the
target, so that v
is now bound to the return value.
But this is wasteful. The local b
is declared just to hold
something that will be copied right out. While a compiler that
combined an "elision" algorithm with interprocedural data flow
analysis could conceivably eliminate all of this, it is much more
practical to allow you to assist the compiler in generating
efficient code by manipulating the return value explicitly,
thus avoiding the local variable and copy constructor altogether.
Using the extended GNU C++ function-definition syntax, you can avoid the
temporary allocation and copying by naming r
as your return value
at the outset, and assigning to its a
field directly:
X m () return r; { r.a = 23; }
The declaration of r
is a standard, proper declaration, whose effects
are executed before any of the body of m
.
Functions of this type impose no additional restrictions; in particular,
you can execute return
statements, or return implicitly by
reaching the end of the function body ("falling off the edge").
Cases like
X m () return r (23); { return; }
(or even `X m () return r (23); { }') are unambiguous, since
the return value r
has been initialized in either case. The
following code may be hard to read, but also works predictably:
X m () return r; { X b; return b; }
The return value slot denoted by r
is initialized at the outset,
but the statement `return b;' overrides this value. The compiler
deals with this by destroying r
(calling the destructor if there
is one, or doing nothing if there is not), and then reinitializing
r
with b
.
This extension is provided primarily to help people who use overloaded operators, where there is a great need to control not just the arguments, but the return values of functions. For classes where the copy constructor incurs a heavy performance penalty (especially in the common case where there is a quick default constructor), this is a major savings. The disadvantage of this extension is that you do not control when the default constructor for the return value is called: it is always called at the beginning.