Const Correctness – The Good, The When, and The… More Good?

const

The use of const is something of a mythical being for some programmers. I’ve seen it used different ways; some throw it around a lot because they know about the ‘good’ but don’t fully grasp the ‘when’.  Then there are those who don’t use it at all because it may feel unnecessary or hard to get used to. I was a mix of both during my cowboy coding days, and since working on more business-orientated projects const-correctness has been beaten into my programming instinct many times over. You’ll quickly realise it’s value when working across teams and very large code bases.

So why the sudden post on programming you ask? It stems from my habit to keep general hand-written notes on useful programming tidbits, especially for something like const-correctness where its usage can be highly situational. By nature I’m quite forgetful, so keeping these notes close by while coding helps maintain a kind of procedure when writing code.  Ironically, my notes can also be victim to forgetfulness. So as a means of self-reference I’ll be trying to move my coding know-how onto the digital domain, where I know it’ll be safe from memory-induced danger of the analogue kind (never mind).

The Good

So what is const good for? There’s no way to really understand this without actually knowing what it does. Simply put, the const keyword prevents objects from being mutated, making them immutable (i.e something that cannot be changed). I really can’t explain the benefits of const better than choorucode  has put it:

It is one extra nail hammered into the code to ensure that the code behaves exactly as envisioned in the head of the programmer. Once the vision of the programmer has been converted to code, const helps in ensuring the correctness of this code by pushing the burden of this checking onto the compiler. Thus bugs can be caught much earlier, at compile time. The const code will also behave much nicer with STL and other libraries that give special emphasis to const. They might have faster and/or more robust implementations for const.

Not only that, but imagine the crazy situation when more than one programmer will be using/modifying the same code base! Not to fear, const not only helps build more robust code, but helps readability too! Clarifying your code with const promises the compiler and other programmers that certain objects will not be modified (or in the case of methods; they won’t mutate the object). The benefits start to pay off once you start seeing the immutable (const) and mutable moving parts churning inside the engine of a method just by glancing over it. Here’s an example of const at work:

void MyClass::Mutate() //Method belonging to MyClass that changes it's instance.
{
    //BOOM! Object mutated!
}
void Foo(MyClass const Object)
{
       Object.mutate(); //COMPILER ERROR - cannot change an unchangable object!
}

The error in Foo() is caught at compile time, so you don’t suffer from a speed penalty or runtime space usage. It’s also particularly useful to use const in function arguments as it prevent silly mistakes from occurring, like the following:

void ComparePosition(float const PosY, float const PosX)
 {
        if(PosX = PosY) //Whoops! Flagged as compiler error, I totally meant ==
        {
             do_something();
        }
 }

If those arguments weren’t prefixed with const nasty results would spew forth. Keep in mind as far as the compiler is concerned, it’s perfectly acceptable syntax to use an assignment operator within a conditional (although most modern compilers will throw a warning). By using const you enlist the compilers help to protect yourself from accidentally doing something you weren’t supposed to be able to do. It saves alot of time debugging, and not only are you making your code more readable and safe, but it’s almost like it fixes itself! (ok maybe not that, but still useful right?)

The When

There really isn’t a “how-to” for when to use const, you should use it as much as possible. A good place to start though is for class accessors. I frequently declare my class inspector methods (i.e getters) as const, like so:

class Clock
{
public:
  Clock();
  ~Clock();
  float GetTime() const; //GetTime should not modify anything, so constify it!

private:
  float time;
};
//Note: You can only suffix const to a method, not a function.
//e.g: void GetTime() const; will not compile.
float Clock::GetTime() const  
{ 
   return time; 
}

By design inspector methods shouldn’t modify anything within the object, clarifying this with const promises the compiler and other programmers that those methods will not modify your non-const objects. Without listing specific examples though, you should const-ify as much as possible. Here are the guidelines I tend to follow:

Whenever possible, const all input parameters to a method that are passed by reference. That is, const all input reference and pointer variables that will not be modified inside the method. Making a pass-by-value input parameter (like int) as const is typically not useful.

void FooClass::Append(FooContainer& const FooObject);

Whenever possible, const all methods that do not change the underlying object.

void FooClass::GetFoo() const;

Whenever possible, const all variables defined inside the method that will not be modified once initialised. This might sound obvious, but people ignore this since it seems like too much work, it is however very useful.

void FooClass::GetFoo() const
{    
    const int max = size();
    
    // ***
}

The… More Good?

A slight topic for confusion (or personal preference, as it were) with const is whether it’s used on the right or the left. The const keyword applies itself to whatever is on the left of it, and if there is nothing on the left, it looks to its right. Take a look at the following examples:

const Object* foo; // (1) foo is a pointer of type Object, which is constant

As opposed to:

Object const * foo; // (2) foo is a pointer of a constant Object

Both (1) and (2) are identical. They both create a pointer of a constant object called foo, the only difference is the placement of const before or after the object type.

So, which way is “correct”? Personally, I prefer putting const after the object type, and to explain why we need to look at how declarations are read in C++. In the following declarations try and interpret what parts are const and what parts are not:

Object * const foo;        
Object const * foo;
const Object * foo;        
Object const * const foo;  

So what proves somewhat difficult here is whether the pointer or the type is constant. It may seem tricky, but the thing to keep in mind is that in C++ you generally read types from right-to-left, for example Object * p  is equivalent to p is a pointer to the type Object or  Object & r  is the same as r is a reference to the type Object. Apply the same concept to const, and things suddenly become much easier:

Object * const foo;        //(1) Read right-to-left:  foo is a constant pointer to Object
Object const * foo;        //(2) Read right-to-left:  foo is a pointer to a constant Object
const Object * foo;        //(3) Read right-to-left:  foo is a pointer to Object, which is constant
Object const * const foo;  //(4) Read right-to-left:  foo is a constant pointer to a constant Object

Notice how (2) and (3) do the same thing, they both initialise a pointer foo to a constant Object, the only difference is felt when reading the declaration as we transliterate the code into english.

Some people prefer putting const before the object type, some people don’t. Neither is right or wrong. Usually people become used to how they place const by some coding standards they’ve had follow, and it simply stuck through habit. Ultimately, it’s entirely up to you which to use, just make sure you stick with it.

A Constant End

Well, that about summarizes everything. I’ve listed a few function prototypes using const for their arguments as reference, and I’ll probably add further glancing references to what I’ll call the appendix for anything const related here in the future. But that’s all from me, have fun const-ifying!

Apendix

Const keyword with function arguments:

void Function1(std::string const val);
void Function2(std::string const& val);
void Function3(std::string const* val);

Awesome (if not the best) const reference:

My C++ FAQ

Advertisements

Posted on 02/05/2013, in Uncategorized. Bookmark the permalink. Leave a comment.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s