Understanding correctly that messy keyword ‘const’​ in C++ (I)

Pablo Correa
Geek Culture
4 min readJun 10, 2021

--

Part one: constant types.

In C++, the qualifier ‘const’ specifies a compile-time constraint that an object or variable cannot be modified. The compiler verifies that the object or variable never changes and stops you when you try to modify it or re-assign it. However, writing ‘const’ correct code is way more challenging than just using the keyword in some lines, and then allowing the compiler to figure out what makes sense. In this three-part guide, you will get some hints on how to use it properly.

During my early days as a C++ programmer, I did not pay so much attention to the keyword ‘const’. I did not even pay so much attention to constants when I was immersed into PASCAL and Delphi programming, maybe because I was still attached to some of my habits from my BASIC days. So for me, C++ ‘const’ was some esoteric qualifier that did not represent so much interest or value. If I defined a variable that I was only going to use inside the body of a function (and I was sure that nothing was not going to change it), why bother myself with making it a constant? Besides, C++ has very awkward and seemingly difficult usages of ‘const’ not worth discovering their meaning in my initial learning curve. Here is a funky example:

//The Most Constant Method
const int *const TMCMethod (const int *const& value) const

If you are confused, do not worry! I promise that we will solve it step-by-step. Even that it is a bit difficult, it is not like that famous quote that makes most C/C++ programmers brains’ melt.

// declare f as array of pointer to function returning pointer 
// to function returning void
void (*(*f[])())()

So…are you ready? Let’s begin with the basics. The first thing to know is that when you declare any variable or object, the qualifier ‘const’ can be written before or after the type.

int const anIntegerConstant = 5;

So the line of code above means for the compiler exactly the same as the following line:

const int anIntegerConstant = 5;

Ok. That was not so hard, right? The rule above applies to anything you want to be constant, including arrays. So, the following lines mean for the compiler exactly the same:

// This style could be confusing
int const anIntegerConstantArray[] = {3,5,4,1,2};
// The style I prefer to use
const int anIntegerConstantArray[] = {3,5,4,1,2};

However, for the sake of clarity, I always put the keyword ‘const’ first. That is the code style I am going to keep from now on.

Let’s move to the next level. You can declare variable pointers to constant types:

int varValue = 5;
const int *aConstant = &varValue;

And of course, it does not matter if the reference value is a constant:

const int constantValue = 5;
const int *aConstant = &constantValue;

You can even have a constant array that points to constant types and increment the pointer:

const int anIntegerConstantArray[] = {3,5,4,1,2}; 
const int *aConstant = anIntegerConstantArray;
// Prints 3 and then increments the pointer
std::cout << aConstant++ << std::endl;
// Prints 5
std::cout << aConstant << std::endl;

However, if you point to a constant type, even the pointer may be changeable, it is not possible to use the dereference operator to change the value it points to. You will get a compiler error because you tried to make an assignment in a read-only location:

const int constantValue = 5;
const int *aConstant = &constantValue;
// This line will not compile
*aConstant = 8;

You can also declare a constant pointer to a variable type. The address stored in the pointer itself is constant, so the pointer has to be initialized when it is declared. Even that is possible to change later the value it points to, it is not possible to change the address itself:

int varValue = 5;
int anotherValue = 6;
int *const aConstantPointer = &varValue;
// This line will compile
*aConstantPointer = 8;
// This line will not compileaConstantPointer = &anotherValue;// Also invalid
aConstantPointer++;

Lastly, you can declare a constant pointer to a constant type. Since the stored address is constant, the pointer needs to be initialized in the declaration. Later, it is not possible to change the value it points to, nor to change the address:

int varValue = 5;
int anotherValue = 6;
const int *const aConstantPointerToConstant = &constantValue;
// This line will not compile
*aConstantPointerToConstant = 8;

// This line will also not compile
aConstantPointerToConstant = &anotherValue;
// Also invalid
aConstantPointerToConstant++;

Ok, so far we solved the first half of our funky example at the beginning of the article. Before we finish, there is the last thing to consider. It is possible to cast away constness, using const casts. They work very similarly to regular typecasts in C++, except that they can not make conversion between types or casting down a class hierarchy.

const char *x = "abcdefg";char *x2 = const_cast<char *>(x) ;

However, there is a better option for changing a constant variable that I will show you in the second part, where we are going to explore how to use constants inside the methods of a class. That’s it for now! Until the next one, happy coding!

--

--

Pablo Correa
Geek Culture

I am a C/C++ Software Developer focused on UX and Audio, trying to see the big picture behind my work by looking how it will affect the whole user experience.