19C. Type Definition and Const Pointers


Type definitions

Typedef

You can give a new name to a type using typedef. Declaration

  typedef existingType newName;
makes newName refer to existingType. For example,
  typedef int* IntPtr;
makes IntPtr mean int*. Declaration
  IntPtr p;
creates variable p of type int*.


What typedef means

A type definition does not call for a textual substitution. Recall that declaration

  int* p, q;
says that p has type int* and q has type int. But
  IntPtr p, q;
says that p and q both have type IntPtr, which is the same as int*. As you can see, having names for pointer types can make a program clearer.

You typically make type definitions outside of functions, often in header files.



Const and pointers

Const pointers

Creating an integer constant
  const int size = 50;
makes it clear that you cannot change the value of 'size'. But what about the following?
  int x = 25;
  const int* p = &x;
Does the const designator indicate that you cannot change p or that you cannot change *p? Would we have to say that x is a constant to do that?

According to the definition of C++, declaration

  const int* p = &x;
says that the program cannot use variable p to change *p. Statements
  int x = 25;
  const int* p = &x;
  *p = 3;
are not allowed because the third one tries to change variable *p.


You are allowed to change the pointer that is stored in a const pointer variable. For example, there is nothing wrong with

  int x = 25, y = 35;
  const int* p = &x;
  …
  p = &y;

Clearly, it is *p that is constant, not p itself.


A const pointer can point to a nonconst variable

There is nothing wrong with creating a const pointer to a non-const variable. For example,
  int x = 25;
  const int* p = &x;
  x = 3;
is fine. The issue is how the program refers to the variable; *p is const but x is not.

You are always free to add a const restriction, but you cannot take it away.


You cannot copy a const pointer into a nonconst variable

Suppose you want to do a loop using a pointer. It might look something like this.
  void loop(const int* ptr)
  {
    const int* p = ptr;
    while(…)
    {
      …
      p = …
    }
  }
The details suppressed with dots are not important here. The point is that variable p must be a const pointer, since it is set equal to a const pointer. You can still change the pointer that is in p. You just can't change *p.


Const and typedefs

Now comes a surprising part of this discussion.

Const with a typedef'd pointer type

After
  typedef int* IntPtr;
  const IntPtr p;
you find that you are allowed to change *p but you are not allowed to change p. Types const int* and const IntPtr are different!

Creating const pointer types

You can get around that strange behavior by doing more typedefs. Declarations
  typedef int* IntPtr;
  typedef const int* ConstIntPtr;
creates two types. Type ConstIntPtr is just like const int*, and declaration
  ConstIntPtr p;
has exactly the same meaning as
  const int* p;
Declaration
  ConstIntPtr p, q;
means the same thing as
  const int* p;
  const int* q;


Summary

Declaration

  typedef oldtype newname
makes newname refer to oldtype.

Declaration

  const double* q = ptr;
means that you cannot use q to change what is stored in variable *q. But you can change the memory address that is stored in q.

Modifier const works differently when it modifies a type name that is defined by typedef.