Pages

Thursday, August 20, 2009

C++: Reference to Pointer

Recently working with some code, I came across an interesting concept - references to pointers. What does that even mean? Why would you need a reference to a pointer - ever?

After spending some time with my friend Google, I found out the answer. Suppose we have these two function definitions, and a main function:
void function_a(int *& a) {
*a += 5;
int * c = new int(7);
a = c;
}
void function_b(int * a) {
*a += 5;
int * c = new int(7);
a = c;
}
int main() {
int * myInt = new int(5);
int * myInt2 = new int(5);

function_a(myInt);
// what is the value of myInt?

function_b(myInt2);
// what is the value of myInt2?

return 0;
}

Analysis

Above, in 'function_a' we're actually passing in 'int *& a', which is a 'reference to a pointer' - a better way to think of this as passing in a 'pointer by reference'. Now, I admit, when I first saw this I thought it was called a 'pointer to a reference' but I'm not really sure what that actually would mean. So for now, just take my word for it that it's called a reference to a pointer. :)

Ok, well if you look at 'function_b', it's passing in it's paramter by pointer only ('int * a'). Both functions do the same operations within their bodies, so whats with the ampersand in function_a? Lets assume that you compiled this application and ran it. Using the int main above, you would expect the value of myInt to be 7 after function_a, right? How about for myInt2? Again, you'd expect it to be 7 after function_b. That's where you're wrong though. After running the main function above you'll get this output:

  • myInt = 7
  • myInt2 = 10

Hooray for unexpected results! The reasoning behind this actually makes sense when you realize this rule for C++:


All parameters are passed by value, unless the ampersand is specified.


Yes, even pointers are passed by value, meaning that a local copy is made for that function. This gets confusing because a pointer simply stores a memory address - and you can change the value at that memory address. The key though, is that if you make a local copy of that memory address in another variable, you can still modify the area in memory that memory address refers to, but now since it's a copy of that, if you try to change the address, it only changes for the scope the variable lives in. Confused? Lets see an example:

int * outside - points to memory at 0xFF9999, and lets say the value at that address is the integer '27'.

suppose we write

int * outside = new int(27);
function_b(outside);  // Using function_b from above
  1. Inside function_b, our local int pointer 'a' now has a copy of that memory address 0xFF9999.
  2. We first add 5 to the value at that address the way we normally would... So, 27+5 = 32. Now 'a' has a value of 32. And so does 'outside', since they both point to the same location. This is what we expected!
  3. Now we initialize int * c = new int(7) - so 'c' has a value of 7 and lets say it has an address of 0x22CCCC.
  4. Then we set the address of 'a' to 'c'. Well 'a' now has the address 0x22CCCC, and consequently the value 7, but we're no longer changing the 'outside' pointer value, since 'a' was a copy of 0xFF9999. So 'outside' still is pointing to 0xFF9999, and 'a' is pointing to '0x22CCCC'.
  5. The function returns, 'outside' now has a value of 32, and the memory at address 0x22CCCC has been leaked since nothing is pointing to it any longer!

How Passing a Pointer by Reference Solves this Problem

When we pass the pointer by reference, as in function_a, the local variable 'a' is no longer a copy of the memory address that 'outside' points to, it literally is the variable 'outside'. Therefore setting the address of 'a' to 'c', will actually change the value of 'outside' to 7, as it changes the address of 'outside'. (You may have noticed that function_a also leaks memory as it never deletes the memory that 'a' pointed to before switching to 'c' as well!)

Hopefully this explanation ends up helping someone out there that may encounter this problem, which seems to be some what not well documented and untaught in basic programming classes in school!

Feel free to post about your experiences with references to pointers below.
Thanks!