By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,996 Members | 1,179 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,996 IT Pros & Developers. It's quick & easy.

Returning by value, returning by reference

P: n/a
When I compile and run the following on my system:
#include <iostream>

static int hello = 78;
int ReturnValue(void)
{
return hello;
}
int& ReturnRef(void)
{
return hello;
}
int main(void)
{
const int& value = ReturnValue();

const int& ref = ReturnRef();

if ( &value == &ref )
{
std::cout << "They're the same!!" << std::endl;
}
else
{
std::cout << "They're different!!" << std::endl;
}

std::system("pause");

}
, it prints "They're different". I'm curious as to why?!
I was thinking along these lines at first:

You can bind a temporary returned from a function to a reference. Therefore,
it's just the same as the function returning by reference, except that it's
const.

As such, I expected the output to be "They're the same!!".
Any thoughts?
-JKop
Jul 22 '05 #1
Share this Question
Share on Google+
19 Replies


P: n/a
JKop posted:
When I compile and run the following on my system:
#include <iostream>

static int hello = 78;
int ReturnValue(void)
{
return hello;
}
int& ReturnRef(void)
{
return hello;
}
int main(void)
{
const int& value = ReturnValue();

const int& ref = ReturnRef();

if ( &value == &ref )
{
std::cout << "They're the same!!" << std::endl;
}
else
{
std::cout << "They're different!!" << std::endl;
}

std::system("pause");

}
, it prints "They're different". I'm curious as to why?!
I was thinking along these lines at first:

You can bind a temporary returned from a function to a reference.
Therefore, it's just the same as the function returning by reference,
except that it's const.

As such, I expected the output to be "They're the same!!".
Any thoughts?
-JKop

Another thought:

A function that returns a const reference.
A function that returns by value.
int Monkey(void)
{
int monkey = 72;

return monkey;
}
const int& Ape(void)
{
int ape = 72;

return ape;
}
They're exactly the same, right? There shouldn't be any difference, eg. an
extra temporary made.
-JKop
Jul 22 '05 #2

P: n/a
"JKop" <NU**@NULL.NULL> wrote in message
news:6q*****************@news.indigo.ie...
....
const int& value = ReturnValue(); .... You can bind a temporary returned from a function to a reference. Therefore, it's just the same as the function returning by reference, except that it's const.

Not the same actually.
The story is more like: the function returned the copy of a value,
eventually stored on the stack. By using a const reference, we are
trying to tell the compiler to avoid copying the value again into
a local variable, and to extend the lifetime of the temporary it
stores a reference to.

The original variable whose copy was returned by "ReturnValue()"
is never accessible from the outside.
hth
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- e-mail contact form
Brainbench MVP for C++ <> http://www.brainbench.com
Jul 22 '05 #3

P: n/a
JKop wrote in news:6q*****************@news.indigo.ie in comp.lang.c++:
When I compile and run the following on my system:
#include <iostream>

static int hello = 78;
int ReturnValue(void)
{
This Function returns a *copy* of 'hello'.
return hello;
}
int& ReturnRef(void)
{
return hello;
}
int main(void)
{
const int& value = ReturnValue();
In the above the compiler creates a temporary in which it stores
a the value returned by ReturnValue. In effect something like:

int temp = ReturnValue();
int const &value = temp;

const int& ref = ReturnRef();

if ( &value == &ref )
{
std::cout << "They're the same!!" << std::endl;
}
else
{
std::cout << "They're different!!" << std::endl;
}

std::system("pause");

}
, it prints "They're different". I'm curious as to why?!
I was thinking along these lines at first:

You can bind a temporary returned from a function to a reference.
This is true, but you conclusion doesen't follow.
Therefore, it's just the same as the function returning by reference,
except that it's const.

Binding temporaries to constant references *isn't* a result
of the way temoraries are created, it happens because the
standard says so, there is hence no "Therefore".
As such, I expected the output to be "They're the same!!".
Any thoughts?


Logic applies to why the language is the way it is, but that
doesn't mean the language is (always) logical.

If you haven't got one already get a good book.
If you haven't got it already get a copy of the C++ Standard.

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #4

P: n/a
JKop wrote in news:5u*****************@news.indigo.ie in comp.lang.c++:

A function that returns a const reference.
A function that returns by value.
This is OK.
int Monkey(void)
{
int monkey = 72;

return monkey;
}

This is UB (it maybe diagnostic (i.e. warning) required).

const int& Ape(void)
{
int ape = 72;

return ape;
'ape' has now been destroyed, the returned reference, referes
to an object that no longer exists.

}
They're exactly the same, right? There shouldn't be any difference,
eg. an extra temporary made.


No.

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #5

P: n/a
Rob Williscroft posted:
Therefore, it's just the same as the function returning by reference,
except that it's const.


Binding temporaries to constant references *isn't* a result
of the way temoraries are created, it happens because the
standard says so, there is hence no "Therefore".


I'll make myself more clear:
int monkey(void);

const int& ape(void);
I wasn't talking about how you've to:

const int& primate = monkey;
-JKop
Jul 22 '05 #6

P: n/a

int monkey = ReturnIntValue();

const int& monkey = ReturnIntValue();
I once heard an argument that the binding-to-a-reference one is better
because it avoids an extra temporary. If this is so, why the hell doesn't
the following print "They're the same!!"?:

#include <iostream>

const int* g_p1;

const int* g_p2;
int Chocolate(void)
{
int monkey = 42;

g_p1 = &monkey;
return monkey;
}
int main(void)
{
const int& cream = Chocolate();

g_p2 = &cream;

if (g_p1 == g_p2)
{
std::cout << "They're the same!!";
}
{
std::cout << "They're different!!";
}

std::system("pause");

}
-JKop

Jul 22 '05 #7

P: n/a
JKop wrote in news:JK*****************@news.indigo.ie in comp.lang.c++:
Rob Williscroft posted:
Therefore, it's just the same as the function returning by reference,
except that it's const.


Binding temporaries to constant references *isn't* a result
of the way temoraries are created, it happens because the
standard says so, there is hence no "Therefore".


I'll make myself more clear:
int monkey(void);

const int& ape(void);
I wasn't talking about how you've to:

const int& primate = monkey;


That *isn't* clearer in any way.
Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #8

P: n/a
Rob Williscroft posted:
JKop wrote in news:5u*****************@news.indigo.ie in comp.lang.c++:

A function that returns a const reference.
A function that returns by value.

This is OK.

int Monkey(void)
{
int monkey = 72;

return monkey; }


This is UB (it maybe diagnostic (i.e. warning) required).


What does UB stand for?

While I'm asking, what does OP stand for?


const int& Ape(void)
{
int ape = 72;

return ape;


'ape' has now been destroyed, the returned reference, referes
to an object that no longer exists.

When you return by value, the object exists until the next ;. When you
return by reference, the object is destroy immediately. Is that what you're
saying? ie.

int ReturnIntValue(void);

const int& ReturnIntRef(void);

void TakesInt(const int);
int main(void)
{
TakesInt( ReturnIntValue() );

//Nothing wrong because the object exists until the next ;

TakesInt( ReturnIntRef() );

//This is undefined behaviour because the object was destroyed
//immediately

}
I don't know why I'm asking the following question, but still absolute
clarity would be nice:

const int ReturnValue(void);
int ReturnValue(void);
They're exactly the same, right? (Yes, I realize how stupid the question
sounds!)

-JKop
Jul 22 '05 #9

P: n/a
Rob Williscroft posted:
JKop wrote in news:JK*****************@news.indigo.ie in comp.lang.c++:
Rob Williscroft posted:
Therefore, it's just the same as the function returning by reference,
except that it's const.
Binding temporaries to constant references *isn't* a result
of the way temoraries are created, it happens because the
standard says so, there is hence no "Therefore".


I'll make myself more clear:
int monkey(void);

const int& ape(void);
I wasn't talking about how you've to:

const int& primate = monkey;


That *isn't* clearer in any way.
Rob.


Anyway, this has been addressed elsewhere in the thread.

END

-JKop
Jul 22 '05 #10

P: n/a
Rob Williscroft wrote:


const int& Ape(void)
{
int ape = 72;

return ape;


'ape' has now been destroyed, the returned reference, referes
to an object that no longer exists.


Indeed. Looks like an example for Item 23 in from Scott Meyers' book
"Effective C++": "Don't try to return a reference when you must return an
object".

--
Chris Gordon-Smith
London
Homepage: http://graffiti.virgin.net/c.gordon-smith/
Email Address: Please see my Home Page
Jul 22 '05 #11

P: n/a
JKop wrote in news:KV*****************@news.indigo.ie in comp.lang.c++:
Rob Williscroft posted:
JKop wrote in news:5u*****************@news.indigo.ie in
comp.lang.c++: [snip]

int Monkey(void)
{
int monkey = 72;

return monkey; }

This is UB (it maybe diagnostic (i.e. warning) required).


What does UB stand for?


Udefined Behaviour, its whaen the Standard gives up and nolonger
determines what behaviour if any your program exhibits.
While I'm asking, what does OP stand for?
Original Poster, the person that started the thread.


const int& Ape(void)
{
int ape = 72;

return ape;
'ape' has now been destroyed, the returned reference, referes
to an object that no longer exists.

When you return by value, the object exists until the next ;


No when you return by value a *copy* is made snd is passed back to the
caller. In the case of int's this is usally done in a CPU register.
In the case of objects to big for a register this is usually done
by havving the caller create a temporary before making the call
and passing (in some way) the address (a pointer to) of the
temorary.

When you
return by reference, the object is destroy immediately. Is that what
you're saying? ie.


Its not to do with returning by reference, in your example 'ape' is
an automatic variable and is destroyed when the block (in this case
the body {} of the fuction 'Ape()') it was created in is left ( the
reurn statment ).

[snip]

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #12

P: n/a
Rob Williscroft posted:
int Monkey(void)
{
int monkey = 72;

return monkey; }

Undefined behaviour???????????????????????????????????
-JKop
Jul 22 '05 #13

P: n/a
JKop posted:

int monkey = ReturnIntValue();

const int& monkey = ReturnIntValue();

Well there's one extra temporary staring me in the face!
Dropped the ball on that one.

With the first one, there's 3 objects. Firstly, there's the int variable
within the function ReturnIntValue. Then there's the temporary returned.
Then there's my monkey variable in main.
With the second, there's 2 objects. Firstly, there's the int variable within
the function ReturnIntValue. Then there's the temporary returned. THIS IS
WHERE IT'S DIFFERENT: I don't create a new variable and copy it over, I hang
on to the temporary.
Which begs the question...

Why must there be a temporary? Why can't it just return the variable from
within the function.
-JKop
Jul 22 '05 #14

P: n/a
JKop posted:
Rob Williscroft posted:
int Monkey(void)
{
int monkey = 72;

return monkey; }

Undefined behaviour???????????????????????????????????
-JKop


Opps I just realized that you were referring to the code that *followed*,
rather than preceeded.

I've gotten the moral of the story here:

int Monkey(void)
{
int monkey = 72;

return monkey;
}
The monkey object gets destroyed straight away even before the function
returns, but a copy is made of it before it's destroyed, this is the
temporary passed to the calling function. This temporary lasts until the
next ; in the calling function, unless it's bound to a reference, as so:

int main(void)
{
const int& monkey = Monkey();
}
In which case, the temporary lasts as long as would an automatic variable if
it were declared in the place of monkey.

-JKop
Jul 22 '05 #15

P: n/a
JKop wrote in news:1F*****************@news.indigo.ie in comp.lang.c++:

Opps I just realized that you were referring to the code that
*followed*, rather than preceeded.
Sorry about that I over quoted.

I've gotten the moral of the story here:

int Monkey(void)
{
int monkey = 72;

return monkey;
}
The monkey object gets destroyed straight away even before the
function returns, but a copy is made of it before it's destroyed, this
is the temporary passed to the calling function. This temporary lasts
until the next ; in the calling function, unless it's bound to a
reference, as so:

int main(void)
{
const int& monkey = Monkey();
}
In which case, the temporary lasts as long as would an automatic
variable if it were declared in the place of monkey.


Yep.

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #16

P: n/a
JKop <NU**@NULL.NULL> wrote in message news:<FO*****************@news.indigo.ie>...
int monkey = ReturnIntValue();

const int& monkey = ReturnIntValue();
I once heard an argument that the binding-to-a-reference one is better
because it avoids an extra temporary. If this is so, why the hell doesn't
the following print "They're the same!!"?:

#include <iostream>

const int* g_p1;

const int* g_p2;
int Chocolate(void)
{
int monkey = 42;

g_p1 = &monkey;
return monkey;
}
int main(void)
{
const int& cream = Chocolate();

g_p2 = &cream;

if (g_p1 == g_p2)
{
std::cout << "They're the same!!";
}
{
std::cout << "They're different!!";
}

std::system("pause");

}
-JKop

Well, many things at work here.

(1) If you want to return by reference, that has to be
explicitly mentioned in the method prototype. So the
chocolate method should have signature as follows:

int &chocolate(void)

(2) You can not return by reference a local variable, in
your case, monkey is a local variable in chocolate
method. SO it should be made global. As a side remark,
the pointer g_p1 will become dangling because monkey
variable will be destroyed once control comes out of
chocolate method.

(3) There is no matching-else to the if statement in the
main(). Also because of the way standard I/O does
buffering, a cout may not result in immediate display
of the string "They are same!" or whatever, put an
endl at the end of cout: cout<<"string"<<endl;

--BG.
Jul 22 '05 #17

P: n/a
> JKop <NU**@NULL.NULL> wrote in message
news:<FO*****************@news.indigo.ie>...
int monkey = ReturnIntValue();

const int& monkey = ReturnIntValue();
I once heard an argument that the binding-to-a-reference one is better
because it avoids an extra temporary. If this is so, why the hell doesn't the following print "They're the same!!"?:

#include <iostream>

const int* g_p1;

const int* g_p2;
int Chocolate(void)
{
int monkey = 42;

g_p1 = &monkey;
return monkey;
}
int main(void)
{
const int& cream = Chocolate();

g_p2 = &cream;

if (g_p1 == g_p2)
{
std::cout << "They're the same!!";
}
{
std::cout << "They're different!!";
}

std::system("pause");

}
-JKop

<<big snip>>
Is this issue still live? Anyway, response to JKop...

g_p1 contains the address of the local variable monkey, which has gone out
of scope when Chocolate returns to main. It may or may not be useable, but
certainly isn't valid, unless you like to program with undefined behaviour.
g_p2 contains the address of the temporary copy of monkey which is being
held because it was returned with the reference cream.
The two variables (the original monkey, now out of scope, and the copy of
monkey held with the reference cream) are in different places. Therefore
g_p1 and g_p2 are different.
Taking the address of a reference to a temporary seems a little bit dicey to
me --- and may well be UB.
--
Gary
Jul 22 '05 #18

P: n/a
JKop wrote:
When I compile and run the following on my system:
#include <iostream>

static int hello = 78;
int ReturnValue(void)
{
return hello;
}
int& ReturnRef(void)
{
return hello;
}
int main(void)
{
const int& value = ReturnValue();

This creates a temporary, and binds 'value' to it.
const int& ref = ReturnRef();

This bind 'ref' to the global variable 'hello'. if ( &value == &ref )
Using the addressof operator on references gives you the address of the
object they reference. Therefore '&value' is the address of the
temporary, and '&ref' is the address of 'hello'.

Change this to 'if (&ref == &hello)' and they should be the same. {
std::cout << "They're the same!!" << std::endl;
}
else
{
std::cout << "They're different!!" << std::endl;
}

std::system("pause");

}
, it prints "They're different". I'm curious as to why?!

Alan
Jul 22 '05 #19

P: n/a
"JKop" <NU**@NULL.NULL> wrote in message
news:Vz*****************@news.indigo.ie...
Why must there be a temporary? Why can't it just return the
variable from within the function.

When you return a (non-static) local variable, the compiler
is allowed to make the local variable and the return-value
temporary the same.
This is called the NRVO (Named Return Value Optimization),
which some compilers do implement.

Try:

#include <iostream>

class Value
{
public:
int m;
Value(int i) : m(i) {}
Value(const Value& o) : m(o.m) { std::cout<<"Value Copied\n"; }
};

Value f()
{
Value v(5);
return v; // return may require copying
}

int main()
{
Value mine = f(); // var init may require copying
return 0;
}

Depending on how smart your compiler is, the previous program
may output "Value Copied" 0 to 2 times.
Things that may help less 'advanced' compiler optimize-out
the copies are to:
- rewrite f()'s body as:
return Value(5);
( Optimizing this out is called RVO (Return Value Optimization)
and is more commonly supported than NRVO ).
- change the type of mine() to a const-reference:
Value const& mine = f();
This may help some compilers optimize-out a copy.
hth -Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- e-mail contact form
Brainbench MVP for C++ <> http://www.brainbench.com
Jul 22 '05 #20

This discussion thread is closed

Replies have been disabled for this discussion.