==============================================================================
Const correctness.
Nick: possible
==============================================================================
   
                           CONST CORRECTNESS IN C++
                                       
   A popular USENET joke goes:
   
     In C, you merely shoot yourself in the foot.
     
     In C++, you accidentally create a dozen instances of yourself and
     shoot them all in the foot. Providing emergency medical care is
     impossible, because you can't tell which are bitwise copies and
     which are just pointing at others and saying, "That's me , over
     there."
     
   While it is true that using the object-oriented features of C++
   requires more thought (and hence, more opportunities to make
   mistakes), the language provides features that can help you create
   more robust and bug-free applications. One of these features is const,
   the use of which I will address in this article.
   
   Used properly with classes, const augments data-hiding and
   encapsulation to provide full compile-time safety; violations of const
   are flagged illegal at compile time, which can save you a lot of grief
   (from side-effects and other accidental modifications of data). Some
   C++ programmers believe const-correctness is a waste of time. If you
   are designing objects or routines for use by other people, then
   whether or not you think it's a waste of time, you ought to make your
   code const-correct. If you don't, then a person who doesn't think
   const-correctness is a waste of time will not be able to use your
   code.
   
   Like most keywords in C++, the const modifier has many shades of
   meaning, depending on context. Used to modify variables, const
   (surprisingly) makes it illegal to modify the variable after its
   initialization. For example:
     _________________________________________________________________
   

int  x = 4;        // a normal variable that can be modified
x = 10;            // legal

const int x = 2;   // const var can be initialized, not modified thereafter
x = 10;            // error - cannot modify const variable

   
     _________________________________________________________________
   
   Thus, const can replace the use of the #define to give names to
   manifest constants. Since preprocessor macros don't provide strong
   compile-time type checking, it is better to use const than #define.
   Also, some debugging environments will display the symbol which
   corresponds to a const value, but for #define constants, they will
   only display the value.
   
   The const keyword is a little more involved when used with pointers. A
   pointer is itself a variable (which holds a memory address); with the
   dereferencing operator, it can be used as a "handle" to the variable
   whose address it holds. Th ere is a semantic difference between "a
   read-only handle to a changeable variable" and a "changeable handle to
   a read-only variable".
     _________________________________________________________________
   

const int x;      // constant int
x = 2;            // illegal - can't modify x

const int* pX;    // changeable pointer to constant int
*pX = 3;          // illegal -  can't use pX to modify an int
pX = &someOtherIntVar;      // legal - pX can point somewhere else

int* const pY;              // constant pointer to changeable int
*pY = 4;                    // legal - can use pY to modify an int
pY = &someOtherIntVar;      // illegal - can't make pY point anywhere else

const int* const pZ;        // const pointer to const int
*pZ = 5;                    // illegal - can't use pZ to modify an int
pZ = &someOtherIntVar;      // illegal - can't make pZ point anywhere else

   
     _________________________________________________________________
   
   You can explicitly circumvent pointers to const objects if you want
   to, but the behavior is undefined.
     _________________________________________________________________
   

int y;
const int* pConstY = &y;  // legal - but can't use pConstY to modify y
int* pMutableY = &y;      // legal - can use pMutableY to modify y
*pMutableY = 42;

   
     _________________________________________________________________
   
   A pointer to a const object can be initialized with a pointer to an
   object that is not const, but not vice versa. In the above code, all
   you're really saying is that you can't use pConstY as a handle to
   modify the data it points to. If y is not const, then you can safely
   modify y via another pointer, pMutableY for instance. Pointing at int
   y with a const int* does not make y const, it just means that you
   can't change y using that pointer. If y is const, however, forcing the
   compiler to let you mess with its value can yield strange results.
   Although you should never write code that does this, you can play
   tricks on the compiler and try to modify const data. All you need to
   do is somehow put the address of the const int into a normal int* that
   you can use to modify the const int.
   
   C++ does not allow you to circumvent const easily because the
   assignment operator can't be used to put the contents of a const int*
   into a normal int* without explicit casts. C++ does not supply a
   standard conversion from a const type to a type that is not const.
   However, any sort of conversion can be specified using explicit type
   casts (including conversions that are unsafe). Thus, the type-system
   in C++ generally will not allow you to put the address of const data
   into a pointer to non-const data.
   
   For example, try to put the address of x, which is const, into a
   normal int* so you can use it to modify the data:
     _________________________________________________________________
   

const int x;             // x cannot be modified

const int* pX = &x;      // pX is the address of a const int
                         // and can't be used to change an int

*pX = 4;                 // illegal - can't use pX to change an int

int* pInt;       // address of normal int
pInt = pX;       // illegal - cannot convert from const int* to int*

   
     _________________________________________________________________
   
   Also, the compiler will not let you take the address of a const
   variable and store it in a pointer to non-const data using the
   address-of operator (&), for the same reason:
     _________________________________________________________________
   

int *pInt;   // address of a normal int
pInt = &x;   // illegal - cannot convert from const int* to int*

   
     _________________________________________________________________
   
   The address-of operator returns a pointer to the variable; if the
   variable is a const int, it returns a const int*. If the variable is
   an int, & returns an int*. C++ makes it difficult to get a pointer to
   t his data which can be used to modify it.
   
   The const keyword can't keep you from purposely shooting yourself in
   the foot. Using explicit type-casting, you can freely blow off your
   entire leg, because while the compiler helps prevent accidental
   errors, it lets you make errors on purpose. C asting allows you to
   "pretend" that a variable is a different type. For example, C
   programmers learn early on that the result of dividing an integer by
   an integer is always an integer:
     _________________________________________________________________
   

int x = 37;
int y = 8;

double quotient = x / y;   // classic mistake, result is rounded to an int
cout << quotient;          // prints " 4.000000"
double quotient = (double)x/y;   // cast result as double so it's not rounded
cout << quotient;          // prints "4.625000"

   
     _________________________________________________________________
   
   With casting, you can force the compiler to let you put the address of
   a const int variable into a normal int*. Remember that const int* and
   int* are, in fact, separate types. So you can cast from a const int*
   to a normal int* and use the pointer to try and modify data. The
   result, however, is undefined. The compiler is free to store constants
   wherever it wants (including non-writeable memory), and if you trick
   the compiler into letting you try to modify the constant, the result
   is undefined. This means that it might work, it might do nothing, or
   it might crash your program.
   
   The following code is a good illustration of how you can blow off your
   leg with forced casting, and confuse yourself in the process.
     _________________________________________________________________
   

const int x = 4;           // x is const, it can't be modified
const int* pX = &x;        // you can't modify x through the pX pointer

cout << x << endl;         // prints "4"

int* pX2 = (int *)pX;      // explicitly cast pX as an int*
*pX2 = 3;                  // result is undefined

cout << x << endl;        // who knows what it prints?

   
     _________________________________________________________________
   
   On my system using , this code compiles and runs without crashing, but
   the x does not appear to be changed by the second assignment; it
   outputs '4' both times.
   
   However, when you look at it more closely, strange things are
   happening. When you run the code, the output (from cout or printf)
   seems to show that x doesn't change in the second assignment. But when
   you step through the code, the debugger shows you that x does, in
   fact, change. So what is happening? If x changes, then why doesn't the
   output statement reflect this change?
   
   Often in such bizarre situations, it is a good idea to look at the
   assembler code that was produced. In Visual C++, compile with the
   /Fa"filename.asm" option to output the assembler with the
   corresponding lines of code into a file so you can look at it. Don't
   panic if you don't know much about assembler - if you know how
   arguments are pushed onto the stack, it's really quite easy to see
   what's happening.
   
   
     _________________________________________________________________
   

ASSEMBLER OUTPUT                       C++ CODE
Mov   eax, DWORD PTR _pX$[ebp]         int* pXX = (int *)pX;
Mov   DWORD PTR _pXX$[ebp], eax
Mov   eax, DWORD PTR _pXX$[ebp]        *pXX = 3;
Mov   DWORD PTR [eax], 3
Push  OFFSET FLAT:?endl@@.........     cout << x << endl;
Push  4

   
     _________________________________________________________________
   
   The important line is "Push 4". The assembler code shows that instead
   of pushing the value of x onto cout's stack frame, it pushes the
   literal constant 4 instead. The compiler assumes that since you
   declared x as const and initialized it as 4, it is free to optimize by
   pushing the literal constant 4 onto the stack rather than having to
   dereference x to get its value. This happens in Visual C++ even with
   all optimization turned off. This code would work fine if we did not
   declare x as const. We could use a const int* to point at a non-const
   int, and have no trouble.
   
   This all goes to show that you shouldn't try to trick your compiler
   with const, because it may trick you instead. This is not a good way
   to write your C++ code. Another way to write functionally equivalent
   code is to use the const_cast operator to remove the const-ness from
   the const int*. The result is the same:
   
   
     _________________________________________________________________
   

const int x = 4;      // x is const, it can't be modified
const int* pX = &x;   // you can't modify x through the pX pointer

cout << x << endl;    // prints "4"

int* pX2 = const_cast < int* > (pX);   // explicitly cast pX as non-const

*pX2 = 3;           // result is undefined
cout << x << endl;   // who knows what it prints?

   
     _________________________________________________________________
   
   It's a good idea to use the const_cast operator. The const_cast
   operator is more specific than normal type-casts because it can only
   be used to remove the const-ness of a variable, and trying to change
   its type in other ways is a compile error. For instance, say that you
   changed x in the above example to an double and changed pX to double*.
   The code would still compile, but pX2 would be treating it as an int.
   It might not cause a problem (because ints and doubles are somewhat
   similar), but the code would certainly be confusing. Also, if you were
   using user-defined classes instead of numeric types, the code would
   still compile, but it would almost certainly crash your program.
   
   Another example of using pointers to play around with const storage is
   when you try to use a char* to modify a string literal. In C++, the
   compiler allows the use of string literals to initialize character
   arrays. A string literal consists of zero or more characters
   surrounded by double quotation marks ("). A string literal represents
   a sequence of characters that, taken together, form a null-terminated
   string. The compiler creates static, internal storage space for the
   string, null-terminates it, and puts the address of this space into
   the char* variable. The type of a literal string is an array of const
   chars.
   
   The C++ standard (section lex.string) states:
   
     
       _______________________________________________________________
     

1 A  string  literal  is  a  sequence  of  characters  (as  defined   in
  _lex.ccon_) surrounded by double quotes, optionally beginning with the
  letter L, as in "..." or L"...".  A string literal that does not begin
  with  L  is  an  ordinary string literal, also referred to as a narrow
  string literal.  An ordinary string literal has type "array of n const
  char"  and  static storage duration (_basic.stc_), where n is the size
  of the string as defined below, and  is  initialized  with  the  given
  characters.   A string literal that begins with L, such as L"asdf", is
  a wide string literal.  A wide string literal has  type  "array  of  n
  const wchar_t" and has static storage duration, where n is the size of
  the string as defined below, and is initialized with the given charac-
  ters.

2 Whether  all  string  literals  are  distinct  (that is, are stored in
  nonoverlapping objects)  is  implementation-defined.   The  effect  of
  attempting to modify a string literal is undefined.

     
       _______________________________________________________________
     
   In the following example, the compiler creates a static storage space
   for the literal string of characters "Hello world" and automatically
   puts a null-character at the end of this space. This is an array of
   const chars. It then puts the starting address of this array into the
   szMyString variable. Then we try to modify this string (wherever it is
   stored) by accessing it via an index into szMyString. This is a Bad
   Thing; the standard does not say where the compiler puts static
   strings. They can go anywhere, possibly in some place in memory that
   you shouldn't be modifying.
     _________________________________________________________________
   

char* szMyString = "Hello world.";
szMyString[3] = 'q';         // undefined, modifying internal static buffer!!!

   
     _________________________________________________________________
   
   In James Coplien's book, Advanced C++ Programming Styles & Idioms, I
   came across the following code (p. 400):
     _________________________________________________________________
   

char *const a = "example 1";   // a const pointer to (he claims) non-const data
a[8] = '2';         // Coplien says this is OK, but it's actually undefined

   
     _________________________________________________________________
   
   Both of these examples happen to work on my system, but you shouldn't
   rely on this kind of code to function correctly. Whether the literal
   strings you point to are explicitly declared const or not, you
   shouldn't try to modify them, because the standard states that they
   are const anyways.
   
   If you've been paying attention, you'll remember that the type-system
   in C++ will not allow you to put the address of const data into a
   pointer to non-const data without using explicit type casts. Example:
   
     _________________________________________________________________
   

   const char constArray[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
   char nonConstArray[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
   char* pArray = constArray;            // illegal
   char* pArray = nonConstArray;         // legal

   
     _________________________________________________________________
   
   If, as the standard says, an ordinary string literal has type "array
   of n const char", then this code should cause a type error:
     _________________________________________________________________
   

   // should be illegal - converts array of 6 const char to char*
   char* pArray = "Hello";

   
     _________________________________________________________________
   
   This appears to be an inconsistency in the language standard. A lot of
   these inconsistencies exist because a lot of old C and C++ code would
   break if the standard were followed to the letter. The standards
   people are afraid to break old code, because it would mean a decrease
   in the popularity of the new language. Hence, you find weird stuff
   like this when you think about it.
   
   To beat this subject to death, notice item 2 in the quote from the
   language standard, about whether strings have to be distinct.
   
   Also, it is legal for implementations to use string pooling, where all
   equal string literals are stored at the same place. For example, the
   help in Visual C++ states:
   
     "The /GF option causes the compiler to pool strings and place them
     in read-only memory. By placing the strings in read-only memory, the
     operating system does not need to swap that portion of memory.
     Instead, it can read the strings back from the image file. Strings
     placed in read-only memory cannot be modified; if you try to modify
     them, you will see an Application Error dialog box. The /GF option
     is comparable to the /Gf option, except that /Gf does not place the
     strings in read-only memory. When using the /Gf option, your program
     must not write over pooled strings. Also, if you use identical
     strings to allocate string buffers, the /Gf option pools the
     strings. Thus, what was intended as multiple pointers to multiple
     buffers ends up as multiple pointers to a single buffer."
     
   To test this, you can write a simple program as follows:
     _________________________________________________________________
   

#include <stdio.h>

int main()
{
   char* szFirst = "Literal String";
   char* szSecond = "Literal String";

   szFirst[3] = 'q';
   printf("szFirst (%s) is at %d, szSecond (%s) is at %d\n",
         szFirst, szFirst, szSecond, szSecond);

   return 0;
}

   
     _________________________________________________________________
   
   On my system, this program outputs:

szFirst (Litqral String) is at 4266616, szSecond (Litqral String) is at 4266616

   Sure enough. Although there was only one change, since string pooling
   was activated, both char* variables pointed to the same buffer. The
   output reflects this.
   
   To get back on track, it is often useful to use const variables when
   you have private data in a class, but you want to easily access the
   data outside of the class without changing it. For example:
     _________________________________________________________________
   

class Person
{
   public:
      Person(char* szNewName)
      {
         // make a copy of the string
         m_szName = _strdup(szNewName);
      };

      ~Person() { delete[] m_szName; };

   private:

      char* m_szName;
};

   
     _________________________________________________________________
   
   Now, what if I wanted to easily print out the person's name? I could
   do the following:
     _________________________________________________________________
   

class Person
{
   public:
      Person(char* szNewName)
      {
         // make a copy of the string
         m_szName = _strdup(szNewName);
      };

      ~Person() { delete[] m_szName; };

      void PrintName()
      {
         cout << m_szName << endl;
      };

   private:

      char* m_szName;
};

   
     _________________________________________________________________
   
   Now I can call Person::PrintName() and it will print the name out to
   the console. There is a design problem with this code, however. It
   builds dependencies on the iostream libraries and the console I/O
   paradigm right into the Person class. A Person inherently has nothing
   to do with console I/O - don't tie the class to it. What if you want
   to print out the name in a Windows or X-Windows application? You'd
   need to change your class, and that reeks.
   
   So, we can do something like the following:
     _________________________________________________________________
   

class Person
{
   public:
      Person(char* szNewName)
      {
         // make a copy of the string
         m_szName = _strdup(szNewName);
      };

      ~Person() { delete[] m_szName; };

      void GetName(char *szBuf, const size_t nBufLen)
      {
         // ensure null termination in the copy
         strncpy(szBuf, m_szName, nBufLen - 1);
      };
   private:
      char* m_szName;
};

   
     _________________________________________________________________
   
   Now we can print the name out by doing something like this:
     _________________________________________________________________
   

Person P("Fred Jones");
char szTheName = new char[256];
P.GetName(szTheName, 256);
cout << szTheName << endl;

   
     _________________________________________________________________
   
   Wow, three lines of code just to print out a name. And I bet you
   didn't even notice that we forgot to delete the dynamic memory for
   szTheName! There must be a better way to do this. Why don't we just
   return a pointer to the string?
     _________________________________________________________________
   

class Person
{
   public:
      Person(char* szNewName)
      {
         // make a copy of the string
         m_szName = _strdup(szNewName);
      };

      ~Person() { delete[] m_szName; };

      char* GetName()
      {
         return m_szName;
      };

   private:

      char* m_szName;
};

   
     _________________________________________________________________
   
   With this, you can print out the code in one line:
     _________________________________________________________________
   

Person P("Fred Jones");
cout << P.GetName() << endl;

   
     _________________________________________________________________
   
   Much shorter, but as you may have noticed, the m_szName variable is
   private inside the Person class! What's the point of declaring it as
   private if you're going to pass out pointers to it? What if you wrote
   a buggy print function that modified what it was printing?
     _________________________________________________________________
   

// this function overwrites szString
// (which may have held the address of dynamically allocated memory)
void MyBuggyPrint(char* szString)
{
   // make a copy of the string and print out the copy
   szString = _strdup(szString);

   cout << szString << endl;

   free (szString);
}

Person P("Fred Jones");
MyBuggyPrint(P.GetName());

   
     _________________________________________________________________
   
   The MyBuggyPrint function makes a new string, puts the new string's
   address in its first parameter, prints it, then deletes it. This
   results in two related problems. We pass in a pointer to the string
   data that was allocated in the Person constructor, the pointer gets
   set to the location of the string copy, which then gets deleted. So
   P.m_szName is left pointing to garbage. Second, since you lose the
   original location of the string pointed to by m_szName, you never free
   the string, so it's a memory leak. Fortunately, the const keyword
   comes in handy in situations like this.
     _________________________________________________________________
   

class Person
{
   public:
      Person(char* szNewName)
      {
         // make a copy of the string
         m_szName = _strdup(szNewName);
      };

      ~Person() { delete[] m_szName; };

      const char* const GetName()
      {
         return m_szName;
      };

   private:

      char* m_szName;
};

Person P("Fred Jones");

MyBuggyPrint(P.GetName());   // error! Can't convert const char* const to char*

   
     _________________________________________________________________
   
   This time, we're returning a const char* const from the class, which
   means that you can't change the pointer to point somewhere else, and
   you can't modify what the pointer points to. Now your code won't even
   compile, because your MyBuggyPrint function expects a char*.
   
   This brings up an interesting point. If you wrote your code this way,
   you'd have to go back and rewrite your MyBuggyPrint function to take a
   const char* const (no doubt fixing it in the process). This is a
   pretty inefficient way to do things, so remember that you should use
   const as you go - don't try to make everything const correct after the
   fact. As you're writing a function like MyBuggyPrint, you should think
   "Hmmm...do I need to modify what the pointer points to? No...do I need
   to point the pointer somewhere else? No...so I will use a const char*
   const argument." Once you start thinking like this, it's easy to do,
   and it will keep you honest. Once you start using const correctness,
   you have to use it everywhere.
   
   With this philosophy, we could further modify the above example by
   having the Person constructor take a const char* const, instead of a
   char*. We could also further modify the GetName member function. We
   can declare it as:
     _________________________________________________________________
   

class Person
{
   public:
      Person(char* szNewName)
      {
         // make a copy of the string
         m_szName = _strdup(szNewName);
      };

      ~Person() { delete[] m_szName; };

      const char* const GetName() const
      {
         return m_szName;
      };

   private:

      char* m_szName;
};

   
     _________________________________________________________________
   
   Declaring a member function as const tells the compiler that the
   member function will not modify the object's data and will not invoke
   other member functions that are not const. The compiler won't take you
   at your word; it will check to make sure that you really don't modify
   the data. You can call a const member function for either a const or a
   non-const object, but you can't call a non-const member function for a
   const object (because it would modify the object).
   
   If we declare GetName() as a const member function, then the following
   code is legal:
     _________________________________________________________________
   

void PrintPerson(const Person* const pThePerson)
{
   cout << pThePerson->GetName() << endl;   // OK
}

// a const-reference is simply an alias to a const variable
void PrintPerson2(const Person& thePerson)
{
   cout << thePerson.GetName() << endl;   // OK
}

   
     _________________________________________________________________
   
   But if we don't declare it as const, then the code won't even compile.
   
     _________________________________________________________________
   

void PrintPerson(const Person* const pThePerson)
{
   // error - non-const member function called
   cout << pThePerson->GetName() << endl;
}

void PrintPerson2(const Person& thePerson)
{
   // error - non-const member function called
   cout << thePerson.GetName() << endl;
}

   
     _________________________________________________________________
   
   Remember that non-static member functions take as their implicit first
   parameter a pointer called this, which points to a specific instance
   of the object. The this pointer is always const - you cannot make this
   point to anything else (in earlier versions of C++, this was legal).
   
   A const member function in class Person would take a const class
   Person* const (const pointer to const Person) as its implicit first
   argument, whereas a non-const member function in class Person would
   take a class Person* const (const pointer to changeable Person) as its
   first argument.
   
   What if you wanted to have a const member function which did an
   expensive calculation and returned the result? It would be nice to be
   able to cache this result and avoid doing the calculation again for
   subsequent calls to the member function. But since it's a const member
   function, you can't store the cached result in the class, because to
   do so, you'd have to modify a member variable (thereby violating
   const). Or can you?
   
   You could make a fake this pointer using explicit casting:
     _________________________________________________________________
   

class MyData
{
   public:
      /*
      the first time, do calculation, cache result in m_lCache, and set
      m_bCacheValid to TRUE in subsequent calls, if m_bCacheValid is true
      then return m_lCache instead of recalculating
      */

      long ExpensiveCalculation() const
      {
         MyData* fakeThis = (MyData*)this;
         fakeThis->m_lCacheValid = TRUE;
         // and so on...
      };

      // change data and set m_bCacheValid to FALSE to force recalc next time
      void ChangeData()
      {
      };

   private:

      long m_lCache;
      bool m_bCacheValid;

};

   
     _________________________________________________________________
   
   This works, but it's ugly. The mutable storage specifier was added for
   this reason. A mutable member variable can be modified even by const
   member functions. With mutable, you can distinguish between "abstract
   const", where the user cannot tell that anything has been changed
   inside the class, and "concrete const", where the implementation will
   not modify anything, period. This caching of results is a perfect
   example of abstract const-ness. Anyone calling the const member
   function will not know or care whether the result has been cached or
   recalculated. For example:
     _________________________________________________________________
   

class MyData
{
   public:
      /*
      the first time, do calculation, cache result in m_lCache, and set
      m_bCacheValid to TRUE in subsequent calls, if m_bCacheValid is true
      then return m_lCache instead of recalculating
      */

      long ExpensiveCalculation() const
      {
         m_lCacheValid = TRUE;
         // and so on...
      };

      // change data and set m_bCacheValid to FALSE to force recalc next time
      void ChangeData()
      {
      };

   private:

      mutable long m_lCache;
      mutable bool m_bCacheValid;

};
