Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.)?
like image 496
mireazma Avatar asked Mar 19 '23 04:03

mireazma


2 Answers

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
like image 54
Some programmer dude Avatar answered Apr 01 '23 15:04

Some programmer dude


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.

like image 39
Shoe Avatar answered Apr 01 '23 16:04

Shoe