Table of Contents

C - C++ 'const' Declaration

The 'const' system is one of the really messy features of C++.

However it is also used to bodge in a substitute for one of the missing features of C++ and there it gets horridly complicated and sometimes frustratingly restrictive.

The following attempts to explain how const is used and why it exists.


Simple Use of ‘const’

Declare a constant as if it was a variable but add const before it.

const int Constant1=96;

NOTE: This will create an integer constant, with the value 96.

  • Such constants are useful for parameters which are used in the program but do not need to be changed after the program is compiled.
  • This has to be initialized immediately in the constructor because, of course, one cannot set the value later as that would be altering it.
  • Using a constant has an advantage over the C preprocessor #define command in that it is understood & used by the compiler itself, not just substituted into the program text by the preprocessor before reaching the main compiler, so error messages are much more helpful.

Using 'const' with Pointers

Const also works with pointers but one has to be careful where const is put as that determines whether the pointer, or what it points to is constant.

const int * Constant2

declares that Constant2 is a variable pointer to a constant integer and:

int const * Constant2

is an alternative syntax which does the same, whereas:

int * const Constant3

declares that Constant3 is constant pointer to a variable integer and:

int const * const Constant4

declares that Constant4 is constant pointer to a constant integer.

NOTE: Basically ‘const’ applies to whatever is on its immediate left (other than if there is nothing there in which case it applies to whatever is its immediate right).

  • The constant pointer to a variable is useful for storage that can be changed in value but not moved in memory.

Use of ‘const’ in Function Return Values

A pointer (constant or otherwise) to a ‘const’ value can be very useful.

If a function which returns a fixed string is written like:

char *Function1()
{ 
  return "Some text";
}

…then the program could crash if it accidentally tried to alter the value doing:

Function1()[1]=’a’;

The solution:

const char *Function1()
{ 
  return "Some text";
}

NOTE: The compiler will spot the error, because the compiler would then know that the value was unalterable.


Where it Gets Messy - in Parameter Passing

Passing a parameter to a function by value

void Subroutine1(int Parameter1)
{ 
  printf("%d",Parameter1);
}

NOTE: Parameter1 is passed in the default C & C++ way - which is a copy.

  • The subroutine can read the value of the variable passed to it but not alter it because any alterations it makes are only made to the copy and are lost when the subroutine ends.
  • Here, the variable original_value would remain unchanged with a value of 5, and not be set to 96 after Subroutine2 is done.
void Subroutine1()
{ 
  original_value = 5;
  Subroutine2(original_value);
}
 
void Subroutine2(int Parameter1)
{ 
  Parameter1=96;
}

Passing a parameter to a function by reference

The addition of an & to the parameter name in C++ (which was a very confusing choice of symbol because an ‘&’ in front of variables elsewhere in C generates pointers!) causes the actual variable itself, rather than a copy, to be used as the parameter in the subroutine and therefore can be written to thereby passing data back out the subroutine.

void Subroutine3(int &Parameter1)
{ 
  Parameter1=96;
}

NOTE: This would set the variable it was called with to 96.

  • To pass an alterable variable in original C, a rather involved method was used.
  • This involved using a pointer to the variable as the parameter then altering what it pointed to was used.
  • This works but requires the every use of the variable in the called routine altered like that and the calling routine also altered to pass a pointer to the variable.
  • It is rather cumbersome. For example:
void Subroutine4(int *Parameter1)
{ 
  *Parameter1=96;
}

But where does ‘const’ come into this?

There is a second common use for passing data by reference or pointer instead of as a copy.

So a subroutine declared as:

void Subroutine4(big_structure_type &Parameter1); 

might be using & because it is going to alter the variable passed to it; or it might just be to save copying time.

To solve this, ‘const’ can be used in the parameter list. E.g.

void Subroutine4(big_structure_type const &Parameter1);

which will cause the variable to be passed without copying but stop it from then being altered.


Messier Still - in the Object Oriented Programming

In Object Oriented Programming, calling a ‘method’ (the Object Oriented name for a function) of an object gives an extra complication.

For example a trivial class, ‘Class1’, defined as:

class Class1
{ 
  void Method1();
  int MemberVariable1;
}

has no explicit parameters at all to ‘Method1’ but calling it in an object in this class might alter ‘MemberVariable1’ of that object if ‘Method1’ happened to be, for example,

void Class1::Method1()
{ 
  MemberVariable1=MemberVariable1+1;
}

The solution to that is to put ‘const’ after the parameter list like:

class Class2
{ 
  void Method1() const;
  int MemberVariable1;
}

Of course one sometimes needs to combine some of these different uses of ‘const’ which can get confusing as in:

const int*const Method3(const int*const&)const; 

where the 5 uses of ‘const’ respectively mean that the variable pointed to by the returned pointer & the returned pointer itself will not be alterable and that the method does not alter the variable pointed to by the given pointer, the given pointer itself & the object of which it is a method!.


Inconveniences of ‘const’

Besides the confusingness of the const syntax, there are some useful things which the system prevents programs doing.

One in particular annoys me because my programs often needed to be optimized for speed.

This is that a method which is declared ‘const’ cannot even make changes to the hidden parts of its object that would not make any changes that would be apparent from the outside.

This includes storing intermediary results of long calculations which would save processing time in subsequent calls to the class’s methods. Instead it either has to pass such intermediary results back to the calling routine to store and pass back next time (messy) or recalculate from scratch next time (inefficient).

In later versions of C++, the mutable keyword was added which enables const to be overridden for this purpose but it totally relies on trusting the programmer to only use it for that purpose so, if you have to write a program using someone else's class which uses ‘mutable’ then you cannot guarantee that ‘mutable’ things will really be constant which renders ‘const’ virtually useless.

One cannot simply avoid using ‘const’ on class methods because ‘const’ is infectious.


References

http://duramecho.com/ComputerInformation/WhyHowCppConst.html

https://www.cprogramming.com/tutorial/const_correctness.html