Thursday, 8 February 2007

How to use the const keyword to make your C++ better

As the title suggests, I firmly believe that the correct usage of const can make many aspects of your C++ program, and indeed programming style, "better". By "better" I mean smaller executables, more robust, faster, safer, sexy, OK so I lied about it being sexy but the rest is true.

Const is a keyword that many C++ programmers don't use, they either forget to use it, don't know how, or they think its "easier" to program without it. Const is there for a reason and using it will bring many advantages to your programs, from design through to development and debugging.

It is quite hard to define what const is. This is because it is a contextual keyword whose meaning changes depending on where it is used in your code. In general terms it means that the object it refers to cannot be modified after its original creation.

So why would anyone want to use const at all? The simplest case of const is where you have a method that returns a pointer to a const object. In this use it will ensure that no one [or class] can modify the object that was returned. This re-enforces good design and can also have positive effects on your code.

OK so how do you use const? As I mentioned earlier it can be a little tricky to understand how const works in all situations, especially if your new to the keyword. Here are a few examples of how and when to use const, and what the desired effect is:

//#define MAX_SIZE 100
const int MAX_SIZE = 100;


Here I use a const int to replace a #define. You should generally try to use const objects rather than #defines for one very good reason. #define does not use type checking, const [object] does, which immediately improves your ability to debug code as the compiler will flag up any type issues at compile time.

MyObject *MyClass::GetMyObject() const
{
return &m_MyObject;
}

One of the main uses of const is its use within function declarations. The following code snippet shows how you can append const to a function declaration to show that the function does not change anything [outside of its own scope]. The benefit of this is that the compiler can create leaner, more efficient, code for that function as well as those calling the function since it knows it will never modify any member variables or objects outside of its own scope. Member functions that are declared const also have the added feature of being the only functions that can be called from a const object. This makes sure that a const object can not modify its contents.

void AnotherClass::Foo(const MyClass &obj)
{
obj.GetMyObject();
}


Above shows another method of using the const keyword, this time as a function argument. Because obj is a const reference to a MyClass object it means that only const member functions of MyClass can be called. If obj had been a pointer then the same would apply.


void AnotherClass::Foo(const MyClass *obj)
{
obj->GetMyObject();
}

If you want to use pointers and you want the pointer itself to be const I.E you can not modify what the pointer points to then you would need to move the const as below.

void AnotherClass::Foo(MyClass* const obj)
{
obj->SetSomething(10);
}


This means that you can call non const member functions of obj but you can't change what it points to. If you want it so you can only call const member funtions and you can't change what the pointer points to then you would need the following

void AnotherClass::Foo(const MyClass* const obj)
{
obj->GetMyObject();
}


This is essentially the same as a const reference and if this is what you require a const reference should be used instead of a pointer. (To find out more about references see Know thy language c++ references).

All of the above also applies to return values from functions. Returning a const object means that it can only be allocated to another const object when it is initialised.....

const MyClass &test = someobject.GiveMeConstObject();

or a copy of it can be made if it is allocated to a variable on the stack

MyClass test = someobject.GiveMeConstObject();


Well that's about it for the use of the const keyword. Remember that const doesn't just tell the compiler what is happening in your code it also tells other people using your code what happens. In the real world the use of const is a must, it provides the compiler with a way of flagging to the user when something is wrong with the code and it allows the developer to protect data.

1 comments:

Panayiotis said...

I wonder what happens if I write:

MyObject *MyClass::GetMyObject() const
{
m_MyObject = ...;
}

I assume the compiler can't catch this at compile time or the 'const' keyword would have been redundant.
So do I get a runtime error or spend two days trying to figure out what's wrong with my program? :)