Writing “const-correct” code will improve the quality and maintainability of your code. It is especially important and useful when writing Object-Oriented code, as objects are often passed around as constant references. Properly declaring non-mutating methods as
const allows you to safely call any
const method on such a reference. It is part of good type-safe practice and good code hygiene. So how do we do it?
First, some definitions:
- mutating: any function or method that alters the state of an object (ie. makes an assignment to any of its data members) is a ‘mutating’ operation. For example, calling a “setter” method is a mutating operation.
- non-mutating: any operation that does not modify the object’s data members. For example, calling a “getter” method, or performing and returning a calculation.
constparameter: if you have a constant reference or pointer to an object, you may not modify it or call any mutating methods on it.
constmethod: a method declared constant promises not to modify the object when called.
constcorrect: writing code that consistently declares methods and parameters
const, wherever possible.
There are two simple rules of thumb to follow:
- If a method does not modify the object’s state, the method should be declared
- If a method or function does not modify a pointer or reference parameter, the parameter should be declared
Together, these two rules ensures that objects are
const as often as possible. Why is this a good thing? It gives the compiler more type information, which can catch potential bugs, and even give opportunities for optimization.
How do you declare a method to be
const? Just add the
const keyword after the normal method declaration, thus:
You declare a function or method parameter
const in the usual way. Note that in C++, references are usually preferred over pointers wherever possible (unless the parameter is optional, so could be
Less Good Example
Let’s use a simple Customer class as an example. This is valid, but not really const-correct code:
There are several opportunities here to add
const qualifiers to the code. The accessor method for
name does not modify the object state, so it can be made into a
const method by adding the keyword at the end of the method signature. The initial value for
name in the constructor, along with the new name in the mutator can both take
const references to strings (instead of passing by-value, which is less efficient).
So the above code becomes:
Once you have a
const reference to an object (such as the
cust parameter above in
getInvoiceCountFor(), you can only call
const methods on that object. For example, the compiler will flag it as an error if you try to call
setName(), as it is a mutating method.
So why go to the extra effort? Doesn’t it mean you can do less with the objects if you go around declaring things
const? Potentially, yes. But there are a number of benefits:
- giving the compiler more type information can help catch potential bugs
- establishes a “contract”, so you know that certain methods or functions will not modify your objects
- acts as a form of documentation, by declaring the behaviour of methods and treatment of parameters
- provides opportunities for optimization by the compiler
By following the two simple rules above, you can write tighter, safer code that is easier to manage.
Author: ChuckD Date: 07/09/2009 03:26:30 PM
Thanks! Well written and very helpful.