const

The const keyword can be used to tell the compiler that a certain variable should not be modified once it has been initialized. It can also be used to declare functions of a class that do not alter any class data.

Usage

It is considered good practice to use const wherever appropriate to protect data from being unintentionally overwritten. Attempting to shoehorn const into a program after it has been written will create a cascade effect. It is best to implement const early in the code development cycle. This brings us to the proper declaration and usage of const.

The const keyword can take on multiple meanings and be used in a variety of locations (even nonsensical places).

Declarations

To understand what the const is protecting, read from right to left.

const char * str; // pointer to characters that cannot be changed (although the pointer can be redirected)
char const * str; // same as above (just an alternate way of writing it)
char * const str; // cannot change the pointer to characters (although the characters themselves can be changed)

Similarly for C++ references (you cannot apply const to a reference, since a reference cannot be redirected):

const char & str; // reference to character that cannot be changed
char const & str; // same as above

This seems easy enough, however more complicated resolutions can be more difficult to interpret. Consider:

char * const * data; // pointer to unchangeable pointer of characters
char const ** data; // pointer to pointer of unchangeable characters
const char ** data; // pointer to pointer of unchangeable characters
char ** const data; // unchangeable pointer to pointer of characters
char * const * const data; // unchangeable pointer to unchangeable pointer of characters

There are some who would have you believe that you MUST place the const after the type, however you are free to place it either before or after the type, if it is a regular non-pointer type (e.g. “char”). Use the format that matches your existing code or your organizations coding standards. Like anything else, just be consistent. If you want the const to apply to the pointer, you must place const after the asterisk.

It is also good practice to declare certain fields of an object to be const if it is a property of the object that does not change over the life of the object.

Parameters

The most common usage of const is to protect data that is pointed to or referenced:

void func ( const MyObject * data ); // MyObject cannot be changed in func
void func ( const MyObject & data ); // MyObject cannot be changed in func

Note that the placement of the const before or after the type is irrelevant. The following is equivalent:

void func ( MyObject const * data ); // same as ( const MyObject * )
void func ( MyObject const & data ); // same as ( const MyOjbect & )

However, placement of the const after the pointer or reference changes what is “const”. A const following a pointer protects only the pointer, not the data to which it points.

void func ( MyObject * const data ); // unnecessary protection of the copied pointer to MyObject

Inside func, you are free to manipulate MyObject, but not the pointer to MyObject. However, since the pointer value is a local to the function (the pointer was passed by value when the function was called), this isn't helpful, as nobody outside the function will be affected by whether you change the pointer or not anyway.

Placing the const after a reference is entirely useless and should be avoided. References cannot be redirected (i.e. they are already implicitly const).

void func ( MyObject & const data ); // useless protection of the reference to MyObject

Here, the const is protecting the reference which can never be manipulated anyway.

Sometimes it is useful to return private data from an object. However, we don't want the private data manipulated outside the class.

const MyObject & MyClass::func ( MyObject & data ); // the MyObject returned by func cannot be changed

Methods

Often instance methods do not manipulate any data in the objects. These methods, which are also known as accessors, should be declared const. The effect of this is that the this pointer inside the method, instead of being a “MyClass *”, will now be a “const MyClass *”, so that they cannot modify the object through the this pointer.

void MyClass::func ( MyOjbect & data ) const; // this function does not manipulate class data

Note that if you have a const object, you may only call const methods on that object. (The reason is that when you call a method, you need to pass a pointer to the object as the this pointer. But if you have a “const MyClass” object, then you can only get a “const MyClass *”, not a “MyClass *”, so you can only call const methods.)

void MyClass::const_func() const;
void MyClass::func();
 
const MyClass object;
 
object.const_func(); // ok
object.func(); // can't call non-const function in a const object

For the same reason, inside a const method, you can only call other const methods of the object.

Related Topics: const_cast, mutable