11

I am currently learning C++ from C++ Primer, and it explains how a reference is an alias to another variable name. It also explains how a pointer points to another variable. It states that the difference between a pointer and a reference is that pointers can be reassigned and references can't.

In the following code example, what can I do with the pointer or reference that I can't do with the other?

double pi = 3.14;
double &piRef = pi;
double *const piPnt = π

//both of these examples are valid and do the same thing
piRef = 3.14159;
*piPnt = 3.14159;

//however, if I attempt to reassign what the pointer points to, it is illegal.
//this is the same as with a reference, as a reference can't be reassigned either
double tau = 6.28;
piPnt = τ

I am aware of the internal differences of each (such as that a pointer is an object, a reference isn't). I am interested in how those differences matter to the programmer beyond a slightly different syntax. As such, this is not a duplicate of this question in which the accepted answer only talks about internal differences.

Community
  • 1
  • 1
john01dav
  • 1,842
  • 1
  • 21
  • 40
  • @juanchopanza The pointer in my example is a const pointer, therefore it can't be reassigned. – john01dav Oct 05 '15 at 06:11
  • But you can use assignment on the reference. Just remember it is an alias for something else. – juanchopanza Oct 05 '15 at 06:12
  • @juanchopanza I can reassign the value the pointer points to. For instance, both `piRef = 3.14159` and `*piPnt = 3.14169` would be valid. A pointer can be const without pointing to a const object. – john01dav Oct 05 '15 at 06:15
  • Yes, that's right. There isn't much difference, except that the pointer is an object in itself, so you can, for example, get its address. The reference has no address of its own. – juanchopanza Oct 05 '15 at 06:21
  • 1
    You can bind a const reference to a temporary. – n. m. could be an AI Oct 05 '15 at 06:26
  • AFAIK, they were added to support operator overloading. Imagine the confusion if `a + b` worked differently from `a.operator +(b)`. (Say, if it worked like `a.operator +(&b)`, in which case you couldn't have an rvalue on the right side of a `+`!) – user253751 Oct 05 '15 at 09:24

3 Answers3

6

From a functional point of view pointers and references are indeed the same thing... they reference an object and are not a copy of that object.

The only real difference in addition to not being able to rebind a reference is that a pointer can be NULL (i.e. it can point to nothing) while a reference is assumed to always reference an object.

You technically can actually end up with a reference that is referencing no object (e.g. passing *p to a function expecting a reference where p is the null pointer) but this is "undefined behavior".

In other words pointers are more "flexible" than references and this allows the compiler to ignore

  • That a reference can change the object it's referencing
  • That a reference can have no object

And this can in some cases produce faster code (however for the second point de-referencing a null pointer is undefined behavior and not a runtime error; the compiler therefore is not mandated to generate code that does something special in this case: that a pointer can actually point to no object is indeed irrelevant from a code generation point of view because it's in the contract between programmer and compiler that this will never happen).

The "price" to pay for the added flexibility of rebinding and having NULLs is that the syntax is (somewhat gratuitously) more annoying.

If the pointer cannot be reassigned (because the pointer itself is const) then there are no practical differences whatsoever except for the more verbose-but-explicit syntax. This because despite being an object a const-declared pointer cannot be altered even using aliasing.

While from a syntactic point of view you can take the address of the const pointer, cast the address to an address of a non-const pointer and change the value pointed to, such an operation would be undefined behavior and whatever happens (e.g. ignoring the assignment) the compiler is going to be right if taken to court :-)

6502
  • 112,025
  • 15
  • 165
  • 265
  • 1
    In what cases would I want to use a const null pointer? If it has no use, it might as well not exist -- it certainly isn't relevant then. – john01dav Oct 05 '15 at 06:18
  • Your two conditions say that the compiler can ignore two things that as far as I know don't exist. A reference can't point to a non-object nor can it change what it is referencing. – john01dav Oct 05 '15 at 06:27
  • 1
    @john01dav: exactly. These things in C++ are impossible (one syntactically and enforced compile time, the other because it's unsupported and undefined behavior) so the compiler can generate better code than the code it would have to generate if they were possible. For example `++x` made many times in a function where `x` is an `int&` doesn't need to ever reload the address of the referenced integer, while with `(*p)++` where `p` is a pointer the the compiler must also consider that `p` could have changed (also possibly because of aliasing). – 6502 Oct 05 '15 at 06:35
  • I suspect they exist in part because they exist C; references are just a more convenient syntax, but there is little point in explicitly disallowing something because an equivalent way of expressing it exists. It's not exactly true that it has no use, though - like the answer says, you can't have null references but you can have null pointers, so they're comparable to final references in Java, and they do get used, if only occasionally. – jaymmer - Reinstate Monica Oct 05 '15 at 06:43
  • 2
    @6502 It doesn't need to consider that p could have changed if p is a const pointer (`double *const p = &someObject;`); – john01dav Oct 05 '15 at 06:43
  • @NeilG Wrong; that would be UB, so the compiler doesn't need to consider it. What you're overlooking is that the object is *declared* `const`, rather than, say, being obtained by dereferencing a `double*const*`. From `[dcl.type.cv]`: "any attempt to modify a const object during its lifetime (3.8) results in undefined behavior". From `[basic.type.qualifier]`: "The presence of a const specifier in a decl-specifier-seq declares an object of const-qualified object type; such object is called a const object." –  Oct 05 '15 at 10:56
  • @Hurkyl: I read the post again. If `p` is a parameter, then it definitely can be const-casted and that's not undefined at all. But if the object is declared const then you're right. – Neil G Oct 05 '15 at 11:03
  • @john01dav: A common case where you might see a "const null pointer" is an optional member of an object. Some constructors may set it to null and others to non-null values. Now if you have only one optional member, it generally is better to implement that pattern via a derived class, but with 5 optional members you'd get 32 variations. – MSalters Oct 05 '15 at 12:43
5

what can I do with the pointer or reference that I can't do with the other?

References allow you to write certain constructors and overload operators:

class X
{
    // copy constructor
    X(const X& a);

    // move constructor
    X(X&& a);

    // copy assignment operator
    X& operator=(const X& a);

    // move assignment operator
    X& operator=(X&& a);
}

(Indeed, operator overloading was the motivating use case for introducing references into C++.)

What is often overlooked is the fact that modern C++ distinguishes between X& (a reference to an lvalue) and X&& (a reference to an rvalue), but there is no such thing as a pointer to an rvalue.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
3

what can I do with the pointer or reference that I can't do with the other?

double *const piPnt = π

The above statement

marks piPnt as a read only variable in memory layout

So, piPnt = &xyz would throw an error now.

But changing the value at the address the pointer points to is still valid.

That is , *piPnt = 56 is fine.

Const Pointers are useful in embedded systems that need to refer to the same memory (port mapping). It's a one time mapping and constant pointers are helpful here.

Now with regards to references:

double &piRef = pi;

You cannot reinitialize a reference in C++. You can assign different value to the object it refers to. This is one and the same object for that reference forever. And this is what you did in your example.

piRef = 3.14159;

A reference cannot be changed to refer to another object after initialization. Note that initialization of a reference is treated very differently from assignment to it. Argument passing (5.2.2) and function value return (6.6.3) are initializations.

Some places where references are useful:

  1. Pointers cannot point to temporaries, the standard expressly forbids doing it. References can bind to temporaries.
  2. A pointer can be NULL while a reference is assumed to always reference an object. You can still return null from a function returning a reference, the compiler would not complain about it, but that is suicidal.
Mat
  • 202,337
  • 40
  • 393
  • 406
basav
  • 1,475
  • 12
  • 20
  • You just seem to be mentioning the similarities between a const pointer and a reference and the differences between a non-const pointer and a reference. I am looking for the differences between a const-pointer and a reference. – john01dav Oct 05 '15 at 06:42