Tag Archives: Pointers

Understanding pointer declarations with const

There is more than one way to declare pointers with the same const, qualification, and this can make reading and writing pointer declarations difficult. For example, what does this mean?

char * const cp;

A simple rule I find useful is this:

Split the expression on the asterisks. If the word const is on the left, then it refers to the pointed-to value. If it’s on the right, then it refers to the pointer.

So looking at our example, the const is on the right of the asterisk, so it is the pointer that is const.

Below are examples of all of the const expression types for a single pointer, showing which assignments are possible. Notice that assigning a string literal to a pointer to non-const produces a warning, while assigning it to a pointer to const does not.

    char *cp0 = "cp0";             // warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
    const char *cp1 = "cp1";       // OK
    cp1[0] = 'f';                  // error: assignment of read-only location ‘* cp1’
    cp1 = NULL;                    // OK
    char * const cp2 = "cp2";      // warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
    cp2[0] = 'f';                  // OK
    cp2 = NULL;                    // error: assignment of read-only variable ‘cp2’
    const char *const cp3 = "cp3"; // OK
    cp3[0] = 'f';                  // error: assignment of read-only location ‘*(const char*)"cp3"’
    cp3 = NULL;                    // error: assignment of read-only variable ‘cp3’
    char const *cp4;               // OK, same as cp1
    cp4[0] = 'f';                  // error: assignment of read-only location ‘* cp4’
    cp4 = NULL;                    // OK

Pointers in C++

The main reasons to use pointers in C++ are:

Polymorphism

Derived class overrides are called when a method is called on a base class pointer (or reference).

Optional objects

A pointer can be NULL or nullptr. This is a useful sentinel value indicating that an object has no value.
References have no equivalent, while value objects would need to use their field values to indicate that they did not have a real value.

Separating compilation units

The size of pointers is known at compile-time without knowing the size of what they’re pointing to.
This means that classes that contain pointers do not need to be recompiled if the pointed to classes are changed.
This is the Pimpl idiom.

Interface with C library

C objects are generally exposed as pointers to structs allocated on the heap, so you need to use pointers to manipulate them.
You can wrap the C object in a smart pointer to make this easier and safer.

Data structures

You need pointers to make data structures like linked lists and binary trees.
To make such a structure it is necessary to be able to associate objects indirectly, which means you can’t use value objects, and also change associations as the data structure is modified, which references don’t allow.

Reference semantics

Mostly, you want to pass an object to a function without copying, and pointers and references allow you to do this.

Note that the first and last advantages are shared by references, while the other 4 are specific to pointers.

Differences Between pointers and references in C++

  1. A pointer can be declared uninitialized, but a reference must be declared referring to something
  2. A pointer can be reassigned, but a reference cannot be reassigned – assigning to it changes the referent
  3. Pointers can be NULL, but there is no equivalent for references – they always need to refer to a valid object
  4. You can take the address of a pointer, but you can’t take the address of a reference (you’ll get the address of the referent)
  5. You can make a pointer to a pointer, or a reference to a pointer, but you can’t make a reference to a reference
  6. You can do arithmetic with pointers, but you can’t do arithmetic with references (it would attempt to do arithmetic with the referent)
  7. You de-reference pointers, but you don’t de-reference references (they are automatically de-referenced)
  8. When you call a function that takes a pointer, you can always see at the call site that the argument is a pointer (because it’s declared as a pointer variable, or you take the address of it), but the creation of a reference by function call isn’t explicit at the call site