Sign in to follow this  
zoner7

Returning a reference

Recommended Posts

zoner7    110
I always thought that you are required to give a function the exact same type that it specifies in its definition. Here is a snippit of code that I was looking at that assigns a vector to a function that asks for a reference.
[source lang=cpp]
string& foo(vector<string>& inventory, int i); 

int main()
{
    vector<string> inventory;
    cout << foo(inventory, 0) << "\n\n";
}


The "vector<string>&" appears to call for a reference to a vector of strings. Inventory is only defined as a vector of strings here: "vector<string> inventory." How can we use inventory as a value for the function inventory, since it isn't a reference? Does this statement say that vector<string>& inventory = vector<string> inventory, that is, does make declare and define a reference?

Share this post


Link to post
Share on other sites
Hodgman    51234
Consider this:
vector<string> inventory;
vector<string>& referenceToInventory = inventory;//!!!

referenceToInventory.resize(10);
if( inventory.size() == 10 )
cout << "yay references work";


On the line commented as "!!!", a reference is created that "aliases" a value.

This is what is happening when you call that function. It wants a reference, you give it a value, so it's reference variable is assigned to/aliases your value.

Share this post


Link to post
Share on other sites
Ariste    296
When you see a reference in a function argument list, think 'pass-by-reference' rather than 'pass a reference.' The two phrases say exactly the same thing, but the first one does a better job of conveying what's really going on: 'the vector is being passed by reference to the function' as opposed to 'the function is receiving a reference to an existing vector.' Both are true, but the former is a more helpful way to think about it.

As for why it works: consider it hand-waving on the part of your compiler. When it sees a function with a pass-by-reference argument, and it sees the function used with syntax for pass-by-value, it waves its little digital fingers and reference-izes the thing for you. This can be a blessing and a curse; on the one hand, you don't have to worry about it. On the other... you probably won't worry about it. Make sure you keep track of when variables are being passed by-reference and by-value, and try to use pass-by-reference-to-const as much as possible.

Share this post


Link to post
Share on other sites
zoner7    110
Quote:
Original post by Hodgman
Consider this:
*** Source Snippet Removed ***

On the line commented as "!!!", a reference is created that "aliases" a value.

This is what is happening when you call that function. It wants a reference, you give it a value, so it's reference variable is assigned to/aliases your value.


awesome. Just as I thought. Now what if i were to give the function a reference to inventory to begin with? Would the function make a reference to my reference? or would it simply use it as opposed to creating a new one?

the former sounds sort of inefficient and pointless, but you never know?

Also, does the same process apply for pointers? If I pass a value to a function that asks for a pointer, will it have a pointer point to my value?

Share this post


Link to post
Share on other sites
Waterwalker    431
Its an optimization. You just call the function with your value. That requires the function to copy the value on the stack. You can think for yourself what that means if you have quite a huge vector. So the optimization is that the function declares its parameter as reference. You still hand it the value but it does not copy the value but uses roughly spoken the memory address of your value to access the data without copying it. You value "gets referenced" by the compiler automatically so you do not need to create a reference yourself.

Share this post


Link to post
Share on other sites
Waterwalker    431
Quote:
Original post by zoner7
Would the function make a reference to my reference? or would it simply use it as opposed to creating a new one?

If you hand in the correct type (a reference in this case) it will use it because there is no need to "reinterpret" the incoming parameter to make its type fit.

Quote:
Original post by zoner7
Also, does the same process apply for pointers? If I pass a value to a function that asks for a pointer, will it have a pointer point to my value?

Same goes here. If the function asks for a pointer and you give it a pointer the function takes it as pointer. But if you try to hand in a value the compiler won't accept that. In can reference values but it is not allowed to make a pointer from a value:

void foo(int *);

int i = 0;

foo(i); // <- wont even compile
foo(&i); // <- is the way to go here, note that now foo can change actual value of i


Note that in this case the & means that you access the address of i as opposed to int &b = i; which would be a reference to i and not a pointer. To create you even more headache you can also create references to pointers [grin] ...

Share this post


Link to post
Share on other sites
Ariste    296
Quote:
Original post by zoner7
awesome. Just as I thought. Now what if i were to give the function a reference to inventory to begin with? Would the function make a reference to my reference? or would it simply use it as opposed to creating a new one?

the former sounds sort of inefficient and pointless, but you never know?

Also, does the same process apply for pointers? If I pass a value to a function that asks for a pointer, will it have a pointer point to my value?


I'm pretty sure that references-to-references are actually forbidden by the C++ standard. I might be crazy, but I think I read that somewhere. So, in answer to your first question: the function would just get a reference to your value, as normal.

As for pointers, think of them just like any other value-type. When you pass a pointer, the pointer is passed by value. Since passing by value creates a copy, the new (copied, function-scope) pointer will point to the same address as the original.

Share this post


Link to post
Share on other sites
zoner7    110

Quote:
Original post by zoner7
Also, does the same process apply for pointers? If I pass a value to a function that asks for a pointer, will it have a pointer point to my value?

Same goes here. If the function asks for a pointer and you give it a pointer the function takes it as pointer.[/quote]

I meant to say what happens when I don't pass the function a pointer. I pass it a value instead of a pointer, even though it calls for a pointer. Will the function make a pointer to my value, just as it does with references in the previous scenario, or will I get a compile error?

Share this post


Link to post
Share on other sites
zoner7    110
Quote:
Original post by Ariste
Quote:
Original post by zoner7
awesome. Just as I thought. Now what if i were to give the function a reference to inventory to begin with? Would the function make a reference to my reference? or would it simply use it as opposed to creating a new one?

the former sounds sort of inefficient and pointless, but you never know?

Also, does the same process apply for pointers? If I pass a value to a function that asks for a pointer, will it have a pointer point to my value?


I'm pretty sure that references-to-references are actually forbidden by the C++ standard. I might be crazy, but I think I read that somewhere. So, in answer to your first question: the function would just get a reference to your value, as normal.

As for pointers, think of them just like any other value-type. When you pass a pointer, the pointer is passed by value. Since passing by value creates a copy, the new (copied, function-scope) pointer will point to the same address as the original.


Would that imply that it is more efficient to pass by reference? If I actually give a function a reference, it does not need to make an extra variable. But if I pass any variable, whether it be a pointer or a value, to a function that calls for a pointer, it is still considered as passing by value and will still create a new pointer.

Share this post


Link to post
Share on other sites
zoner7    110
Quote:

foo(i); // <- wont even compile
foo(&i); // <- is the way to go here, note that now foo can change actual value of i



so this code essentially creates a pointer to a reference of a variable?

basically we have:

pointer -----> reference = value

Share this post


Link to post
Share on other sites
Waterwalker    431
Quote:
Original post by zoner7
Would that imply that it is more efficient to pass by reference? If I actually give a function a reference, it does not need to make an extra variable. But if I pass any variable, whether it be a pointer or a value, to a function that calls for a pointer, it is still considered as passing by value and will still create a new pointer.

NO [smile]


MyClass mc;
MyClass &rmc = mc;
MyClass *pmc = &mc;

// bad, needs to copy MyClass however big it is
// call: foo(mc)
void foo(MyClass mc);

// good, no need to copy, but is allowed to globally modify what you hand in as mc
// call: foo(mc) or foo(rmc);
void foo(MyClass &mc);

// good, no need to copy andguarantees not to globally modify what you hand in as mc
// call: foo(mc) or foo(rmc);
void foo(const MyClass &mc);

// use a pointer as parameter, now it gets confusing a bit
// call: foo(&mc) // can globally change mc but not mc's address
// call: foo(pmc) // can globally change pmc but not pmc's address
void foo(MyClass *mc);

// use a pointer as const parameter
// call: foo(&mc) // can not globally change mc
// call: foo(pmc) // can not globally change pmc
void foo(const MyClass *mc);

// and now a pointer to a pointer which is even more confusing at first
// call: foo(&pmc); // can globally change mc and its address also
void foo(MyClass **ppmc);


While the ** parameter seems to be weird at first it is quite common to let a function create instances for NULL pointers you hand in:


void foo(MyClass **pmc)
{
*pmc = new MyClass;
}

MyClass *pmc = 0;
foo(&pm);

Share this post


Link to post
Share on other sites
Waterwalker    431
Quote:
Original post by zoner7
Quote:

foo(i); // <- wont even compile
foo(&i); // <- is the way to go here, note that now foo can change actual value of i



so this code essentially creates a pointer to a reference of a variable?

No.


int i = 0; // is what you call a value
int &ri = i; // is a reference to the value i
int *pi = &i; // is a pointer pointing to i's memory address


Thus foo(&i) calls the function and hands in a pointer pointing to i's memory address. I know its confusing at first because in C the & sign is used for different things. When put behind the type declaration it creates a reference to a value. When put after the = operator (which is implicitely present when you put a variable as parameter to a function) it access the memory address of the value it precedes thus effectively creating a pointer.

Share this post


Link to post
Share on other sites
zoner7    110
thank you guys so much more the detailed and quite promptly given help. I understand the basics... the double ** might take a few more read throughs to digest. Thank you guys.

Share this post


Link to post
Share on other sites
DevFred    840
Quote:
Original post by zoner7
If I actually give a function a reference

That's impossible. Whenever you write a reference variable in source code, it denotes the referent, not the reference it self.

int i = 5;
int& r = i;
// From now on it does not matter if you write i or r
// They both denote the same place in memory

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this