Function returning a reference

J

JKop

unsigned int CheesePlain(void)
{
unsigned int const chalk = 42;

return chalk;
}


unsigned int& CheeseRef(void)
{
unsigned int const chalk = 42;

return chalk;
}


int main(void)
{
unsigned int plain = CheesePlain();

unsigned int ref = CheeseRef();
}



Now, consider that the return type is not unsigned int, but some other class
name that prints out stuff via cout in its constructor, copy constructor,
assignment operator. Will you find that there's a difference in the two
separate printouts, ie. that the "plain" one will create one more temporary
than the reference version?


-JKop
 
P

Petec

JKop wrote:
unsigned int& CheeseRef(void)
{
unsigned int const chalk = 42;

return chalk;
}

Very bad. This function returns a reference to an object that is destroyed
right after return.
int main(void)
{
unsigned int plain = CheesePlain();

unsigned int ref = CheeseRef();

'ref' is not a reference:
unsigned int& ref = CheeseRef();
But the returned reference is still invalid.
}



Now, consider that the return type is not unsigned int, but some
other class name that prints out stuff via cout in its constructor,
copy constructor, assignment operator. Will you find that there's a
difference in the two separate printouts, ie. that the "plain" one
will create one more temporary than the reference version?

Doesn't matter, since it's incorrect code. ;)

- Pete
 
A

Alan Johnson

JKop said:
unsigned int CheesePlain(void)
{
unsigned int const chalk = 42;

return chalk;
}


unsigned int& CheeseRef(void)
{
unsigned int const chalk = 42;

return chalk;
}

I imagine a worthwhile compiler will not compile CheeseRef, at least not
without giving you quite a few warnings. First, the return type is not
const correct. Second, you are returning a reference to a local variable.
int main(void)
{
unsigned int plain = CheesePlain();

unsigned int ref = CheeseRef();
}



Now, consider that the return type is not unsigned int, but some other class
name that prints out stuff via cout in its constructor, copy constructor,
assignment operator. Will you find that there's a difference in the two
separate printouts, ie. that the "plain" one will create one more temporary
than the reference version?


-JKop


Let me propose a slight modification that may or may not provide the
answers you are wanting.

unsigned int CheesePlain()
{
unsigned int const chalk = 42;

return chalk;
}

int main(void)
{
unsigned int &ref = CheesePlain();
unsigned int plain = CheesePlain();
}


I've swapped the order because I want to talk about them in this order.
The first assignment creates a temporary, and copies the value of
'chalk' into it. If, as you propose, these were objects with
constructors, the temporary's copy constructor would be called. The
lifetime of the temporary is the same as the lifetime of the reference
bound to it, so when ref goes out of scope at the end of main, the
destructor should be called.

The second assignment is actually a bit more complicated, and the
precise behavior is not defined. One version of what could happen goes
like this. A temporary is created to hold the return value, and 'chalk'
is copied into it (copy constructor). Then, the temporary is used to
initialize 'plain' (copy constructor). The temporary then gets
destroyed, and its destructor is called. However, the implementation is
allowed (but not required) to construct the return value directly into
'plain', *even if the copy constructor or destructor have side effects*
(such as printing something)! So, depending on your implementation, you
may or may not see the temporary getting constructed and destructed.

Alan
 
A

Alan Johnson

Alan said:
I imagine a worthwhile compiler will not compile CheeseRef, at least not
without giving you quite a few warnings. First, the return type is not
const correct. Second, you are returning a reference to a local variable.




Let me propose a slight modification that may or may not provide the
answers you are wanting.

unsigned int CheesePlain()
{
unsigned int const chalk = 42;

return chalk;
}

int main(void)
{
unsigned int &ref = CheesePlain();
unsigned int plain = CheesePlain();
}


I've swapped the order because I want to talk about them in this order.
The first assignment creates a temporary, and copies the value of
'chalk' into it. If, as you propose, these were objects with
constructors, the temporary's copy constructor would be called. The
lifetime of the temporary is the same as the lifetime of the reference
bound to it, so when ref goes out of scope at the end of main, the
destructor should be called.

The second assignment is actually a bit more complicated, and the
precise behavior is not defined. One version of what could happen goes
like this. A temporary is created to hold the return value, and 'chalk'
is copied into it (copy constructor). Then, the temporary is used to
initialize 'plain' (copy constructor). The temporary then gets
destroyed, and its destructor is called. However, the implementation is
allowed (but not required) to construct the return value directly into
'plain', *even if the copy constructor or destructor have side effects*
(such as printing something)! So, depending on your implementation, you
may or may not see the temporary getting constructed and destructed.

Alan


As a followup, here is what the standard has to say about it. Excerpt
from 12.8/15 :

"This elision of copy operations is permitted in the following
circumstances (which may be combined to eliminate multiple copies):

— in a return statement in a function with a class return type, when the
expression is the name of a non-volatile automatic object with the same
cv-unqualified type as the function return type, the copy operation can
be omitted by constructing the automatic object directly into the
function’s return value

— when a temporary class object that has not been bound to a reference
(12.2) would be copied to a class object with the same cv-unqualified
type, the copy operation can be omitted by constructing the temporary
object directly into the target of the omitted copy"

Alan
 
D

DaKoadMunky

unsigned int &ref = CheesePlain();

Doesn't this need to be a reference to const in order for the temporary to be
bound to it?
 
R

Rob Williscroft

Alan Johnson wrote in in comp.lang.c++:
int main(void)
{
unsigned int &ref = CheesePlain();
unsigned int plain = CheesePlain();
}


I've swapped the order because I want to talk about them in this order.
The first assignment creates a temporary, and copies the value of
'chalk' into it. If, as you propose, these were objects with
constructors, the temporary's copy constructor would be called. The
lifetime of the temporary is the same as the lifetime of the reference
bound to it, so when ref goes out of scope at the end of main, the
destructor should be called.

Maybe I've missed someting up-thread, but if this is meant to be C++
the first line of main() needs to be:

unsigned int const &ref = CheesePlain();

As temporaries can't be *bound* to non-constant references.

Note: Some compiler (MSVC) allow the above non-standard code as
a so called "language extension".

Rob.
 
A

Alan Johnson

DaKoadMunky said:
Doesn't this need to be a reference to const in order for the temporary to be
bound to it?

Absolutely. That was an oversight on my part. Thanks for the correction.

Alan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,170
Messages
2,570,924
Members
47,464
Latest member
Bobbylenly

Latest Threads

Top