## Thursday, November 3, 2011

### The Reference-to-Pointer Syntax in C++

The syntax of pointer declarations is sometimes difficult to decipher, just consider the following three, elementary cases:
• int *p
• int (*p)
• int (*p)()

## Example 1

`int *p;`
This is actually an array of two int pointers. We can also think of this as a pointer to two consecutive int pointers.

```int *p;

int *a = new int;
*a = 21;
int *b = new int;
*b = 22;

p = a;
p = b;

std::cout << *p << std::endl;          // 21
std::cout << *p << std::endl;          // 22

int **q = p;

std::cout << **q << std::endl;
std::cout << **(q + 1) << std::endl;

delete a;
delete b;```
http://codepad.org/6c07RgKf

## Example 2

`int (*p);`
This is a pointer to an array of two ints. Just as in the first example, we can think of this a pointer to a pointer, since an array is basically a const pointer.

```int n;
n = 4;
n = 7;

int (*p) = &n;

std::cout << (*p) << std::endl;       // 4
std::cout << (*p) << std::endl;       // 7

// or ...

std::cout << **p << std::endl;           // 4
std::cout << *(*p + 1) << std::endl;     // 7```
http://codepad.org/UDcH5cIQ

## Example 3

`int (*p)();`
This is a pointer to a function returning an int.
```int takeThisInt()
{
return 123;
}

// ...

int (*p)() = &takeThisInt;
int x = p();                      // note the parentheses
std::cout << x << std::endl;      // 123```
http://codepad.org/iL701mg5

# Pointer-to-member-function syntax

This pointer-to-member-function syntax in C++ is not exactly making things more intuitive. Here is an example:
`void (SomeClass::*x)(int) const = &SomeClass::func2;`
Hmm… Let's take a look at the context in which this statement appears.
```class SomeClass
{
public:
void func1(int x) const { std::cout << "func 1: " << x; }
void func2(int x) const { std::cout << "func 2: " << x; }
void func3(int x) const { std::cout << "func 3: " << x; }
};

void callSomeFunction(void (SomeClass::*m)(int) const)
{
SomeClass obj;
(obj.*m)(1);
}

int main()
{
void (SomeClass::*x)(int) const;
x = &SomeClass::func2;
callSomeFunction(x);         // func 2: 1
return 0;
}```
http://codepad.org/eUtSGfbV

In main(), void (SomeClass::*x)(int) const introduces a pointer (named x) to a const member function of SomeClass that returns void and takes an int as parameter. Then, &SomeClass::func2 takes the address of func2, which happens to fit this description. Finally, in callSomeFunction(), the supplied function pointee is called with the argument 1 on the stack allocated object.

A typedef can help to make this a bit more readable:
`typedef void (SomeClass::*SomeClassMember)(int) const;`
The program now reads:
```class SomeClass
{
public:
void func1(int x) const { std::cout << "func 1: " << x; }
void func2(int x) const { std::cout << "func 2: " << x; }
void func3(int x) const { std::cout << "func 3: " << x; }
};

typedef void (SomeClass::*SomeClassMember)(int) const;

void callSomeFunction(SomeClassMember m)
{
SomeClass obj;
(obj.*m)(1);
}

int main()
{
SomeClassMember x = &SomeClass::func2;
callSomeFunction(x);
return 0;
}```
Ok, this post was supposed to be about the reference-to-pointer syntax.

# Reference vs. Pointer

Pointers are memory addresses with type information. The type specifies the kind of data stored in the pointed-to address. References are typically implemented as pointers by the compiler, but on the syntactic level there are several differences:
• A reference can't, once created, be changed to reference another object.
```int n = 1;
int *p = &n;    // p points to n
int k = 2;
p = &k;         // p now points to k instead

int &r = n;     // r will always reference n```
• References cannot be null.
```int *p = new int;
*p = 123;
int &x = *p;     // x is now a local reference to p
x = 5;

std::cout << *p << std::endl;          // 5

delete p;
p = 0;           // pointer is now NULL

if (p) {         // we can't do this with a reference
*p = 1;
}

x = 3;           // undefined behavior```
• References must be initialized when created, and cannot be uninitialized.
`int &ref;  // error: ‘ref’ declared as reference but not initialized `

# Why reference-to-pointer?

Let's look at some different function declarations to see how the reference-to-pointer syntax can be useful.
• void takeInt(int x);
• void takeIntRef(int &r);
• void takePtr(int *p);
• void takePtrToPtr(int **p);
• void takeRefToPtr(int *&rp);

```void takeInt(int x);
void takeIntRef(int &r);
void takePtr(int *p);```
The first three cases are straighforward:

1. The int is passed by value, which means that a local copy is made.
2. The int is passed by reference, the local name acts as an alias for the original variable.
3. A pointer is passed, similar to passing a reference but less safe.

Note that a pointer is actually passed by value, i.e., only a copy of the pointer is passed to the function. The address of the int's memory location is copied to the local pointer p.
` void takePtrToPtr(int **p);`
This is a bit more interesting. A pointer to a pointer is passed. Suppose that a points to b, and b points to an int.

a → b → int

Passing (a) to the function, we can now change not only the original int pointee, but also the pointer (b) itself. Here is an example:
```void takePtrToPtr(int **p)
{
int *x = new int;
*x = 123;
*p = x;
}

int main()
{
int n = 1;
int *p = &n;
assert(p == &n);
takePtrToPtrcout << *p;      // 123
delete p;             // no leaks ^_^

return 0;
}```
Finally,
`void takeRefToPtr(int *&rp);`
is similar to the pointer-to-pointer approach, but with a slightly more friendly syntax. We are now passing a reference to the pointer to takeRefToPtr().
```void takeRefToPtr(int *&rp)
{
int *x = new int;
*x = 123;
rp = x;
}

int main()
{
int n = 55;
int *p = &n;
takeRefToPtr(p);
assert(p != &n);
std::cout << *p << std::endl;        // 123;
delete p;

return 0;
}```
Note how the function changes the the original pointer p.

We could think of the relationship
• int *x ↔ int *&x

as similar to that between
• int x ↔ int &x.

Finally, here is a program that demonstrates the use of the reference-to-pointer syntax:
```#include <iostream>
#include <assert.h>

static int five = 5;
static int nine = 9;

void takeInt(int x)
{
x = 0;
}

void takeIntRef(int &r)
{
r = 0;
}

void takePtr(int *p)
{
*p = 1;
p = &five;
}

void takePtrToPtr(int **p)
{
**p = 789;
*p = &five;
}

void takeRefToPtr(int *&rp)
{
*rp = 1;
rp = &nine;
}

int main()
{
int n = 123;
takeInt(n);
// local copy is modified
std::cout << n << std::endl;
// 123 (value unchanged)

takeIntRef(n);
// value passed by reference, original is modified
std::cout << n << std::endl;
// 0 (assigned in function)

int *pt = &n;
// pt points to n
takePtr(pt);
// pointer is passed by value

assert(pt == &n);
// pointer has not changed (p still points to n) ...
std::cout << n << std::endl;
// 1 ... but pointee has

takePtrToPtr(&pt);
// pass a pointer to pt (= pointer to a pointer to n)
assert(pt != &n);
// this time the pointer has changed,
// pt now no longer points to n

std::cout << *pt << std::endl;
// 5
assert(pt == &five);
// indeed, pt points to the static "five"

std::cout << n << std::endl;
// 789 (changed in first line of takePtrToPtr)

takeRefToPtr(pt);
// pass a pointer by reference
std::cout << *pt << std::endl;
// 9 (pt is now modified in function)

return 0;
}```
http://codepad.org/3OD0sVvw

#### 1 comments:

何念泰 said...

Great Explain!