What are the differences between a pointer variable and a reference variable?

Pointers are just another type of object, and like any object in C++, they can be a variable. References on the other hand are never objects, only variables.

Commented Jun 16, 2012 at 10:14 This compiles without warnings: int &x = *(int*)0; on gcc. Reference can indeed point to NULL. Commented Aug 13, 2012 at 9:00 reference is a variable alias Commented Dec 23, 2013 at 8:53 I like how the very first sentence is a total fallacy. References have their own semantics. Commented Jun 1, 2014 at 1:58

44 Answers 44

  1. A pointer can be re-assigned:
int x = 5; int y = 6; int *p; p = &x; p = &y; *p = 10; assert(x == 5); assert(y == 10); 
A reference cannot be re-bound, and must be bound at initialization:
int x = 5; int y = 6; int &q; // error int &r = x; 
int x = 0; int &r = x; int *p = &x; int *p2 = &r; assert(p == p2); // &x == &r assert(&p != &p2); 
 int **pp; // OK, pointer to pointer int &*pr; // ill-formed, pointer to reference 
int *ap[]; // OK, array of pointers int &ar[]; // ill-formed, array of references 
int x = 0; int y = 0; int *p = &x; int *q = &y; int **pp = &p; **pp = 2; pp = &q; // *pp is now q **pp = 4; assert(y == 4); assert(x == 2); 
/* the code below is undefined; your compiler may optimise it * differently, emit warnings, or outright refuse to compile it */ int &r = *static_cast(nullptr); // prints "null" under GCC 10 std::cout // prints "not null" under GCC 10 std::cout << (f(*static_cast(nullptr)) ? "not null" : "null")  
const int &x = int(12); // legal C++ int *y = &int(12); // illegal to take the address of a temporary. 
community wiki

What's a C++ reference (for C programmers)

A reference can be thought of as a constant pointer (not to be confused with a pointer to a constant value!) with automatic indirection, ie the compiler will apply the * operator for you.

All references must be initialized with a non-null value or compilation will fail. It's neither possible to get the address of a reference - the address operator will return the address of the referenced value instead - nor is it possible to do arithmetics on references.

C programmers might dislike C++ references as it will no longer be obvious when indirection happens or if an argument gets passed by value or by pointer without looking at function signatures.

C++ programmers might dislike using pointers as they are considered unsafe - although references aren't really any safer than constant pointers except in the most trivial cases - lack the convenience of automatic indirection and carry a different semantic connotation.

Consider the following statement from the C++ FAQ:

Even though a reference is often implemented using an address in the underlying assembly language, please do not think of a reference as a funny looking pointer to an object. A reference is the object. It is not a pointer to the object, nor a copy of the object. It is the object.

But if a reference really were the object, how could there be dangling references? In unmanaged languages, it's impossible for references to be any 'safer' than pointers - there generally just isn't a way to reliably alias values across scope boundaries!

Why I consider C++ references useful

Coming from a C background, C++ references may look like a somewhat silly concept, but one should still use them instead of pointers where possible: Automatic indirection is convenient, and references become especially useful when dealing with RAII - but not because of any perceived safety advantage, but rather because they make writing idiomatic code less awkward.

RAII is one of the central concepts of C++, but it interacts non-trivially with copying semantics. Passing objects by reference avoids these issues as no copying is involved. If references were not present in the language, you'd have to use pointers instead, which are more cumbersome to use, thus violating the language design principle that the best-practice solution should be easier than the alternatives.

31.5k 22 22 gold badges 109 109 silver badges 132 132 bronze badges answered Feb 27, 2009 at 21:26 169k 36 36 gold badges 184 184 silver badges 241 241 bronze badges @kriss: No, you can also get a dangling reference by returning an automatic variable by reference. Commented Nov 2, 2010 at 6:14

@kriss: It's virtually impossible for a compiler to detect in the general case. Consider a member function that returns a reference to a class member variable: that's safe and should not be forbidden by the compiler. Then a caller that has an automatic instance of that class, calls that member function, and returns the reference. Presto: dangling reference. And yes, it's going to cause trouble, @kriss: that's my point. Many people claim that an advantage of references over pointers is that references are always valid, but it just isn't so.

Commented Nov 2, 2010 at 13:15

@kriss: No, a reference into an object of automatic storage duration is very different from a temporary object. Anyway, I was just providing a counter-example to your statement that you can only get an invalid reference by dereferencing an invalid pointer. Christoph is correct -- references are not any safer than pointers, a program which uses references exclusively can still break type safety.

Commented Nov 2, 2010 at 15:15 References are not a kind of pointer. They are a new name for an existing object. Commented Jul 20, 2011 at 1:28

@catphive: true if you go by language semantics, not true if you actually look at the implementation; C++ is a far more 'magical' language that C, and if you remove the magic from references, you end up with a pointer

Commented Jul 23, 2011 at 9:07

If you want to be really pedantic, there is one thing you can do with a reference that you can't do with a pointer: extend the lifetime of a temporary object. In C++ if you bind a const reference to a temporary object, the lifetime of that object becomes the lifetime of the reference.

std::string s1 = "123"; std::string s2 = "456"; std::string s3_copy = s1 + s2; const std::string& s3_reference = s1 + s2; 

In this example s3_copy copies the temporary object that is a result of the concatenation. Whereas s3_reference in essence becomes the temporary object. It's really a reference to a temporary object that now has the same lifetime as the reference.

If you try this without the const it should fail to compile. You cannot bind a non-const reference to a temporary object, nor can you take its address for that matter.

31.5k 22 22 gold badges 109 109 silver badges 132 132 bronze badges answered Sep 11, 2008 at 21:43 Matt Price Matt Price 45.1k 9 9 gold badges 39 39 silver badges 44 44 bronze badges but whats the use case for this ? Commented Oct 22, 2009 at 14:10

Well, s3_copy will create a temporary and then copy construct it into s3_copy whereas s3_reference directly uses the temporary. Then to be really pedantic you need to look at the Return Value Optimization whereby the compiler is allowed to elide the copy construction in the first case.

Commented Oct 22, 2009 at 18:14

@digitalSurgeon: The magic there is quite powerful. The object lifetime is extended by the fact of the const & binding, and only when the reference goes out of scope the destructor of the actual referenced type (as compared to the reference type, that could be a base) is called. Since it is a reference, no slicing will take place in between.

Commented Jan 14, 2010 at 17:06

Update for C++11: last sentence should read "You cannot bind a non-const lvalue reference to a temporary" because you can bind a non-const rvalue reference to a temporary, and it has the same lifetime-extending behaviour.

Commented Nov 10, 2013 at 20:14

@AhmadMushtaq: The key use of this is derived classes. If there is no inheritance involved, you might as well use value semantics, which will be cheap or free due to RVO/move construction. But if you have Animal x = fast ? getHare() : getTortoise() then x will face the classic slicing problem, while Animal& x = . will work correctly.

Commented Nov 2, 2017 at 11:04

Apart from syntactic sugar, a reference is a const pointer (not pointer to a const ). You must establish what it refers to when you declare the reference variable, and you cannot change it later.

Update: now that I think about it some more, there is an important difference.

A const pointer's target can be replaced by taking its address and using a const cast.

A reference's target cannot be replaced in any way short of UB.

This should permit the compiler to do more optimization on a reference.

answered Sep 11, 2008 at 20:07 user3458 user3458

I think this is the best answer by far. Others talk about references and pointers like they are different beasts and then lay out how they differ in behavior. It doesn't make things any easier imho. I've always understood references as being a T* const with different syntactic sugar (that happens to eliminate a lot of * and & from your code).

Commented Jan 10, 2017 at 1:34

"A const pointer's target can be replaced by taking its address and using a const cast." Doing so is undefined behavior. See stackoverflow.com/questions/25209838/… for details.

Commented Jun 22, 2018 at 4:51

Trying to change either the referent of a reference or the value of a const pointer (or any const scalar) is equality illegal. What you can do: remove a const qualification that was added by implicit conversion: int i; int const *pci = &i; /* implicit conv to const int* */ int *pi = const_cast(pci); is OK.

Commented Jun 29, 2018 at 16:00

The difference here is UB versus literally impossible. There is no syntax in C++ that would let you change what reference points at.

Commented Jun 29, 2018 at 16:03

Not impossible, harder, you can just access the memory area of the pointer that is modeling that reference and change its content. That can certainly be done.

Commented Nov 17, 2018 at 21:39

Contrary to popular opinion, it is possible to have a reference that is NULL.

int * p = NULL; int & r = *p; r = 1; // crash! (if you're lucky) 

Granted, it is much harder to do with a reference - but if you manage it, you'll tear your hair out trying to find it. References are not inherently safe in C++!

Technically this is an invalid reference, not a null reference. C++ doesn't support null references as a concept as you might find in other languages. There are other kinds of invalid references as well. Any invalid reference raises the spectre of undefined behavior, just as using an invalid pointer would.

The actual error is in the dereferencing of the NULL pointer, prior to the assignment to a reference. But I'm not aware of any compilers that will generate any errors on that condition - the error propagates to a point further along in the code. That's what makes this problem so insidious. Most of the time, if you dereference a NULL pointer, you crash right at that spot and it doesn't take much debugging to figure it out.

My example above is short and contrived. Here's a more real-world example.

class MyClass < . virtual void DoSomething(int,int,int,int,int); >; void Foo(const MyClass & bar) < . bar.DoSomething(i1,i2,i3,i4,i5); // crash occurs here due to memory access violation - obvious why? >MyClass * GetInstance() < if (somecondition) return NULL; . >MyClass * p = GetInstance(); Foo(*p); 

I want to reiterate that the only way to get a null reference is through malformed code, and once you have it you're getting undefined behavior. It never makes sense to check for a null reference; for example you can try if(&bar==NULL). but the compiler might optimize the statement out of existence! A valid reference can never be NULL so from the compiler's view the comparison is always false, and it is free to eliminate the if clause as dead code - this is the essence of undefined behavior.

The proper way to stay out of trouble is to avoid dereferencing a NULL pointer to create a reference. Here's an automated way to accomplish this.

template T& deref(T* p) < if (p == NULL) throw std::invalid_argument(std::string("NULL reference")); return *p; >MyClass * p = GetInstance(); Foo(deref(p)); 

For an older look at this problem from someone with better writing skills, see Null References from Jim Hyslop and Herb Sutter.

For another example of the dangers of dereferencing a null pointer see Exposing undefined behavior when trying to port code to another platform by Raymond Chen.

answered Sep 11, 2008 at 21:06 Mark Ransom Mark Ransom 306k 44 44 gold badges 413 413 silver badges 642 642 bronze badges

The code in question contains undefined behavior. Technically, you cannot do anything with a null pointer except set it, and compare it. Once your program invokes undefined behavior, it can do anything, including appearing to work correctly until you are giving a demo to the big boss.

Commented Sep 12, 2008 at 16:00

mark has a valid argument. the argument that a pointer could be NULL and you therefor have to check is not real either: if you say a function requires non-NULL, then the caller has to do that. so if the caller doesn't he is invoking undefined behavior. just like mark did with the bad reference

Commented Feb 27, 2009 at 21:14

The description is erroneous. This code might or might not create a reference that is NULL. Its behavior is undefined. It might create a perfectly valid reference. It might fail to create any reference at all.

Commented Aug 20, 2011 at 11:41

@David Schwartz, if I were talking about the way things had to work according to the standard, you'd be correct. But that's not what I'm talking about - I'm talking about actual observed behavior with a very popular compiler, and extrapolating based on my knowledge of typical compilers and CPU architectures to what will probably happen. If you believe references to be superior to pointers because they're safer and don't consider that references can be bad, you'll be stumped by a simple problem someday just as I was.

Commented Aug 22, 2011 at 2:11

Dereferencing a null pointer is wrong. Any program that does that, even to initialize a reference is wrong. If you are initializing a reference from a pointer you should always check that the pointer is valid. Even if this succeeds the underlying object may be deleted at any time leaving the reference to refer to non-existing object, right? What you are saying is good stuff. I think the real issue here is that reference does NOT need to be checked for "nullness" when you see one and pointer should be, at minimum, asserted.

Commented Mar 22, 2017 at 14:07

You forgot the most important part:

member-access with pointers uses ->
member-access with references uses .

foo.bar is clearly superior to foo->bar in the same way that vi is clearly superior to Emacs :-)

31.5k 22 22 gold badges 109 109 silver badges 132 132 bronze badges answered Sep 11, 2008 at 22:10 Orion Edwards Orion Edwards 123k 65 65 gold badges 242 242 silver badges 338 338 bronze badges

@Orion Edwards >member-access with pointers uses -> >member-access with references uses . This is not 100% true. You can have a reference to a pointer. In this case you would access members of de-referenced pointer using -> struct Node < Node *next; >; Node *first; // p is a reference to a pointer void foo(Node*&p) < p->next = first; > Node *bar = new Node; foo(bar); -- OP: Are you familiar with the concepts of rvalues and lvalues?

Commented Sep 12, 2008 at 12:57 Smart Pointers have both . (methods on smart pointer class) and -> (methods on underlying type). Commented Apr 9, 2014 at 9:11 why is that . and -> has something to do with vi and emacs :) Commented Aug 21, 2016 at 0:45

@artM - it was a joke, and probably doesn't make sense to non-native english speakers. My apologies. To explain, whether vi is better than emacs is entirely subjective. Some people think vi is far superior, and others think the exact opposite. Similarly, I think using . is better than using -> , but just like vi vs emacs, it's entirely subjective and you can't prove anything

Commented Aug 25, 2016 at 21:41

@user3840170 it's a joke :-) This may be hard to believe, but back in the early days of stack overflow (note the answer is dated september 2008) people used to have a sense of humour and it was a nice site to hang out on. To be honest it's hard to believe that some pedant hasn't marked this answer as deleted by now

Commented Jan 4, 2021 at 23:12

References are very similar to pointers, but they are specifically crafted to be helpful to optimizing compilers.

void maybeModify(int& x); // may modify x in some way void hurtTheCompilersOptimizer(short size, int array[]) < // This function is designed to do something particularly troublesome // for optimizers. It will constantly call maybeModify on array[0] while // adding array[1] to array[2]..array[size-1]. There's no real reason to // do this, other than to demonstrate the power of references. for (int i = 2; i < (int)size; i++) < maybeModify(array[0]); array[i] += array[1]; >> 

An optimizing compiler may realize that we are accessing a[0] and a[1] quite a bunch. It would love to optimize the algorithm to:

void hurtTheCompilersOptimizer(short size, int array[]) < // Do the same thing as above, but instead of accessing array[1] // all the time, access it once and store the result in a register, // which is much faster to do arithmetic with. register int a0 = a[0]; register int a1 = a[1]; // access a[1] once for (int i = 2; i < (int)size; i++) < maybeModify(a0); // Give maybeModify a reference to a register array[i] += a1; // Use the saved register value over and over >a[0] = a0; // Store the modified a[0] back into the array > 

To make such an optimization, it needs to prove that nothing can change array[1] during the call. This is rather easy to do. i is never less than 2, so array[i] can never refer to array[1]. maybeModify() is given a0 as a reference (aliasing array[0]). Because there is no "reference" arithmetic, the compiler just has to prove that maybeModify never gets the address of x, and it has proven that nothing changes array[1].

It also has to prove that there are no ways a future call could read/write a[0] while we have a temporary register copy of it in a0. This is often trivial to prove, because in many cases it is obvious that the reference is never stored in a permanent structure like a class instance.

Now do the same thing with pointers

void maybeModify(int* x); // May modify x in some way void hurtTheCompilersOptimizer(short size, int array[]) < // Same operation, only now with pointers, making the // optimization trickier. for (int i = 2; i < (int)size; i++) < maybeModify(&(array[0])); array[i] += array[1]; >> 

The behavior is the same; only now it is much harder to prove that maybeModify does not ever modify array[1], because we already gave it a pointer; the cat is out of the bag. Now it has to do the much more difficult proof: a static analysis of maybeModify to prove it never writes to &x + 1. It also has to prove that it never saves off a pointer that can refer to array[0], which is just as tricky.

Modern compilers are getting better and better at static analysis, but it is always nice to help them out and use references.

Of course, barring such clever optimizations, compilers will indeed turn references into pointers when needed.

EDIT: Five years after posting this answer, I found an actual technical difference where references are different than just a different way of looking at the same addressing concept. References can modify the lifespan of temporary objects in a way that pointers cannot.

F createF(int argument); void extending() < const F& ref = createF(5); std::cout ; 

Normally temporary objects such as the one created by the call to createF(5) are destroyed at the end of the expression. However, by binding that object to a reference, ref , C++ will extend the lifespan of that temporary object until ref goes out of scope.

answered Sep 1, 2013 at 3:44 Cort Ammon Cort Ammon 10.7k 33 33 silver badges 46 46 bronze badges

True, the body does have to be visible. However, determining that maybeModify does not take the address of anything related to x is substantially easier than proving that a bunch of pointer arithmetic does not occur.

Commented Sep 11, 2013 at 4:27

I believe the optimizer already does that "a bunch of pointer arithemetic does not occur" check for a bunch of other reasons.

Commented Sep 11, 2013 at 4:32

"References are very similar to pointers" - semantically, in appropriate contexts - but in terms of generated code, only in some implementations and not through any definition/requirement. I know you've pointed this out, and I don't disagree with any of your post in practical terms, but we have too many problems already with people reading too much into shorthand descriptions like 'references are like/usually implemented as pointers'.

Commented Oct 11, 2015 at 17:31

I have a feeling that someone wrongly flagged as obsolete a comment along the lines of void maybeModify(int& x) < 1[&x]++; >, which the other comments above are discussing

Commented Dec 3, 2015 at 23:28

Actually, a reference is not really like a pointer.

A compiler keeps "references" to variables, associating a name with a memory address; that's its job to translate any variable name to a memory address when compiling.

When you create a reference, you only tell the compiler that you assign another name to the pointer variable; that's why references cannot "point to null", because a variable cannot be, and not be.

Pointers are variables; they contain the address of some other variable, or can be null. The important thing is that a pointer has a value, while a reference only has a variable that it is referencing.

Now some explanation of real code:

int a = 0; int& b = a; 

Here you are not creating another variable that points to a ; you are just adding another name to the memory content holding the value of a . This memory now has two names, a and b , and it can be addressed using either name.

void increment(int& n) < n = n + 1; >int a; increment(a); 

When calling a function, the compiler usually generates memory spaces for the arguments to be copied to. The function signature defines the spaces that should be created and gives the name that should be used for these spaces. Declaring a parameter as a reference just tells the compiler to use the input variable memory space instead of allocating a new memory space during the method call. It may seem strange to say that your function will be directly manipulating a variable declared in the calling scope, but remember that when executing compiled code, there is no more scope; there is just plain flat memory, and your function code could manipulate any variables.

Now there may be some cases where your compiler may not be able to know the reference when compiling, like when using an extern variable. So a reference may or may not be implemented as a pointer in the underlying code. But in the examples I gave you, it will most likely not be implemented with a pointer.

31.5k 22 22 gold badges 109 109 silver badges 132 132 bronze badges answered Sep 19, 2008 at 12:23 Vincent Robert Vincent Robert 36k 15 15 gold badges 83 83 silver badges 122 122 bronze badges

A reference is a reference to l-value, not necessarily to a variable. Because of that, it's much closer to a pointer than to a real alias (a compile-time construct). Examples of expressions that can be referenced are *p or even *p++

Commented Mar 2, 2009 at 16:27

Right, I was just pointing the fact that a reference may not always push a new variable on the stack the way a new pointer will.

Commented Mar 3, 2009 at 20:36

@VincentRobert: It will act the same as a pointer. if the function is inlined, both reference and pointer will be optimized away. If there's a function call, the address of the object will need to be passed to the function.

Commented Feb 13, 2012 at 23:08 int *p = NULL; int &r=*p; reference pointing to NULL; if(r)<> -> boOm ;) Commented Oct 4, 2015 at 12:37

This focus on the compile stage seems nice, until you remember that references can be passed around at runtime, at which point static aliasing goes out of the window. (And then, references are usually implemented as pointers, but the standard doesn't require this method.)

Commented Oct 11, 2015 at 17:35

A reference can never be NULL .

9,379 15 15 gold badges 51 51 silver badges 76 76 bronze badges answered Sep 11, 2008 at 20:12 RichS RichS

See Mark Ransom's answer for a counter-example. This is the most often asserted myth about references, but it is a myth. The only guarantee that you have by the standard is, that you immediately have UB when you have a NULL reference. But that is akin to saying "This car is safe, it can never get off the road. (We don't take any responsibility for what may happen if you steer it off the road anyway. It might just explode.)"

Commented Jun 13, 2014 at 11:36

@cmaster: In a valid program, a reference cannot be null. But a pointer can. This is not a myth, this is a fact.

Commented Aug 8, 2014 at 4:42

@Mehrdad Yes, valid programs stay on the road. But there is no traffic barrier to enforce that your program actually does. Large parts of the road are actually missing markings. So it's extremely easy to get off the road at night. And it is crucial for debugging such bugs that you know this can happen: the null reference can propagate before it crashes your program, just like a null pointer can. And when it does you have code like void Foo::bar() < virtual_baz(); >that segfaults. If you are not aware that references may be null, you can't trace the null back to its origin.

Commented Dec 29, 2014 at 10:43 int *p = NULL; int &r=*p; reference pointing to NULL; if(r)<> -> boOm ;) – Commented Oct 4, 2015 at 12:43

@sree int &r=*p; is undefined behavior. At that point, you don't have a "reference pointing to NULL," you have a program that can no longer be reasoned about at all.

Commented Mar 28, 2017 at 18:46

There is a semantic difference that may appear esoteric if you are not familiar with studying computer languages in an abstract or even academic fashion.

At the highest-level, the idea of references is that they are transparent "aliases". Your computer may use an address to make them work, but you're not supposed to worry about that: you're supposed to think of them as "just another name" for an existing object and the syntax reflects that. They are stricter than pointers so your compiler can more reliably warn you when you about to create a dangling reference, than when you are about to create a dangling pointer.

Beyond that, there are of course some practical differences between pointers and references. The syntax to use them is obviously different, and you cannot "re-seat" references, have references to nothingness, or have pointers to references.

answered Oct 29, 2014 at 17:17 Lightness Races in Orbit Lightness Races in Orbit 384k 77 77 gold badges 659 659 silver badges 1.1k 1.1k bronze badges

While both references and pointers are used to indirectly access another value, there are two important differences between references and pointers. The first is that a reference always refers to an object: It is an error to define a reference without initializing it. The behavior of assignment is the second important difference: Assigning to a reference changes the object to which the reference is bound; it does not rebind the reference to another object. Once initialized, a reference always refers to the same underlying object.

Consider these two program fragments. In the first, we assign one pointer to another:

int ival = 1024, ival2 = 2048; int *pi = &ival, *pi2 = &ival2; pi = pi2; // pi now points to ival2 

After the assignment, ival, the object addressed by pi remains unchanged. The assignment changes the value of pi, making it point to a different object. Now consider a similar program that assigns two references:

int &ri = ival, &ri2 = ival2; ri = ri2; // assigns ival2 to ival 

This assignment changes ival, the value referenced by ri, and not the reference itself. After the assignment, the two references still refer to their original objects, and the value of those objects is now the same as well.

3,892 7 7 gold badges 23 23 silver badges 35 35 bronze badges answered May 20, 2011 at 19:26 Kunal Vyas Kunal Vyas 1,579 1 1 gold badge 23 23 silver badges 40 40 bronze badges "a reference always refers to an object" is just completely false Commented Jul 21, 2017 at 18:29

A reference is an alias for another variable whereas a pointer holds the memory address of a variable. References are generally used as function parameters so that the passed object is not the copy but the object itself.

 void fun(int &a, int &b); // A common usage of references. int a = 0; int &b = a; // b is an alias for a. Not so common to use. 
answered Jan 1, 2013 at 17:45 fatma.ekici fatma.ekici 2,797 5 5 gold badges 30 30 silver badges 31 31 bronze badges

The direct answer

What is a reference in C++? Some specific instance of type that is not an object type.

What is a pointer in C++? Some specific instance of type that is an object type.

An object type is a (possibly cv-qualified) type that is not a function type, not a reference type, and not cv void.

It may be important to know, object type is a top-level category of the type universe in C++. Reference is also a top-level category. But pointer is not.

Pointers and references are mentioned together in the context of compound type. This is basically due to the nature of the declarator syntax inherited from (and extended) C, which has no references. (Besides, there are more than one kind of declarator of references since C++ 11, while pointers are still "unityped": & + && vs. * .) So drafting a language specific by "extension" with similar style of C in this context is somewhat reasonable. (I will still argue that the syntax of declarators wastes the syntactic expressiveness a lot, makes both human users and implementations frustrating. Thus, all of them are not qualified to be built-in in a new language design. This is a totally different topic about PL design, though.)

Otherwise, it is insignificant that pointers can be qualified as a specific sorts of types with references together. They simply share too few common properties besides the syntax similarity, so there is no need to put them together in most cases.

Note the statements above only mentions "pointers" and "references" as types. There are some interested questions about their instances (like variables). There also come too many misconceptions.

The differences of the top-level categories can already reveal many concrete differences not tied to pointers directly:

A few more special rules on references: