mireazma
mireazma

Reputation: 556

I'm trying to relate C++ reference to pointer

Before saying it would be a duplicate question and downvote (as it happened before), I searched and found nothing alike.
I, like many others, am trying to learn the uses of C++ reference variables and to relate them to pointers. I found it easier to make a table and I need to know whether it needs to be amended.

                   int *n   int n    int &n    caller/local
void foo(int *n)     n       &n        &n          caller
void foo(int n)     *n        n         n           local
void foo(int &n)    *n        n         n          caller

The table wants to reflect all legal passed parameters.

[1,1]: passing by reference (trivial)  
[1,2]: passing by reference  
[1,3(1)]: passing by reference, an is an address(?)  
[1,3(2)]: passing by reference, as n is used as alias(?)  
[2,1]: passing by value, as dereferencing  
[2,2]: passing by value (trivial)  
[2,3(1)]: passing by value, using value of n (where n is an alias)  
[2,3(2)]: passing by value (dereferencing n, which is an address)  
[3,1(1)]: passing by reference, as foo accepts address  
[3,1(2)]: passing by reference, reference of value at address n  
[3,2(1)]: passing by reference (trivial)  
[3,2(2)]: passing by reference, as foo accepts address or reference  
[3,3]: passing by reference (trivial, as argument matches parameter exactly)  
  1. Are the table and explanations correct?
  2. Are there any cases left out of the table (except for derived ones like *&n, pointer to pointer etc.)?

Upvotes: 4

Views: 219

Answers (3)

Tony Delroy
Tony Delroy

Reputation: 106254

Maybe I'm interpreting your table wrong, but assuming you're inside the three functions on the left, and want to get an int* to n, use n, and bind a reference to the int value accessed via n respectively:

Your original table

                   int *n   int n   int &n
void foo(int *n)     n       &n      n/&n
void foo(int n)     *n       n      n/*n
void foo(int &n)    n/*n     n/&n      n

Given the function signatures on the left, you have the following mistakes:

In foo(int* n):

  • to get an int you want *n not &n
  • you must bind any new int&s to *n

In foo(int n)

  • to get a pointer to n you want &n not *n
  • to bind an int& to n you want n, not *n
  • do note that n is a local, copied and different from the caller's n

In foo(int& n):

  • to get a pointer to n you want &n not n or *n
  • to use n you just want n not/never &n

So, I'd write the table like this (I've appended columns for address of n and whether n is the n from the calling context or a local copy)

Suggested corrected table

                    int*   int    int& n2 = ...    int* p = ...   caller/local
void foo(int* p_n)   p_n   *p_n      *p_n            p_n             caller
void foo(int n)      &n     n         n              &n              local
void foo(int& n)     &n     n         n              &n              caller

I'm not convinced such a table has much utility in clarifying the role of references and pointers though.

UPDATE: your comment explains you wanted the table to communicate the "passing form", which I take to be the code you'd need inside the caller of foo. The correct table for that should be:

                   int *n   int n   int &n    caller/local
void foo(int *n)     n       &n      &n          caller
void foo(int n)     *n       n       n           local
void foo(int &n)    *n       n       n           caller

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409482

A function

void foo(int& n);

does not accept an address (a pointer), and not literals either.

So you can't call it like

int a = ...;
foo(&a);  // Trying to pass a pointer to a function not taking a pointer

or

foo(1);  // Passing R-value is not allowed, you can't have a reference to a literal value

There is an exception though, if you have a constant reference, like

int foo(const int& n);

then literal values are allowed, because then the referenced value can't be changed.


Likewise for

void foo(int* n);

you must pass a pointer.

So for example:

int a = ...;
int& ra = a;   // ra references a

foo(&a);  // OK
foo(&ra); // OK
foo(a);   // Fail, a is not a pointer
foo(ra);  // Fail, ra is not a pointer
foo(1);   // Fail, the literal 1 is not a pointer

And for the last:

void foo(int n);

With examples:

int a = ...;
int& ra = a;   // ra references a
int* pa = &a;  // pa points to a

foo(a);   // OK, the value of a is copied
foo(ra);  // OK, the value of the referenced variable is copied
foo(*pa); // OK, dereferences the pointer, and the value is copied
foo(pa);  // Fail, passing a pointer to a function not expecting a pointer
foo(1);   // OK, the literal value 1 is copied

Upvotes: 5

Shoe
Shoe

Reputation: 76308

Overloaded operator* and operator&

Both operator& (unary) and operator* (unary) can be overloaded.

This means that if n is a class type type, then *n can literally have any form including, but not limited to type*, type&, type.

An example (stupid, but still a valid example) would be:

struct type {
    int x;
};

int& operator&(type& t) {
    return t.x;
}

Live demo

Indirection

You can also have infinite number of pointer indirections. In which case *n, **n, ***n might also yield Type* as well as Type&.

As an example, given two functions:

void func_ptr(int*) {}
void func_ref(int&) {}

and the following objects:

int a;
int* b = &a;
int** c = &b;
int*** d = &c;

then, any of the following is valid:

func_ptr(b);
func_ptr(*c);
func_ptr(**d);

func_ref(*b);
func_ref(**c);
func_ref(***d);

Live demo

Conclusion

Are the table and explanations correct? Are there any cases left out of the table (except for derived ones like *&n, pointer to pointer etc.)?

Therefore the table not only is incomplete, but cannot possibly contain all possible cases.

Upvotes: 1

Related Questions