Programming Tips: Const Correctness
Const correctness, the disciplined use of const modifiers when declaring variables and functions, is a practice that most experienced programmers would tell you is a good idea. However, const correctness often ends up being a technique that many programmers never actually use, even when they know they should. The is due in a large part to the rather all-or-nothing nature of const correctness. Once you have non-const correct functions floating around your project, it becomes harder to have them interact with const correct code without degrading the const correctness of that code.
Writing const correct code basically boils down to using const declarations for variables and parameters you never expect to change and for member functions that you expect to never modify their own class data.
For example, a function with const parameters:
void AddFloats( const float a, const float b, float& result )
{
result = a + b;
}
Now, if you ever try to set values to a or b within the AddFloats() function, you’ll get a compiler error telling you about your presumed folly. This is, of course, a highly contrived example. Even if you do change the values for a or b, they are copies of the original values passed into AddFloats() and don’t pose any particular danger if they are changed. But, in the case of a function using non-basic types, the value of const declarations become more apparent:
void AddVectors( const Vector3& a, const Vector3& b, Vector3& result )
{
result = a + b;
}
In this version, the const helps protect you from overwriting the values of the original Vector3s being passed into AddVectors(). Of course, you could just not pass a and b as Vector3 references, but in that case, you would pay the cost of copying the entire contents of a and b (being Vector3s, probably 3 floats) onto the stack instead of just their addresses. In a speed-critical section of code, that sort of difference is crucial.
The other spot where I find const correctness powerful is in the declaration of const functions:
class GameCharacter
{
public:
const Vector3& GetPosition() const;
void SetPosition( const Vector3& newPosition );
private:
Vector3 m_Position;
};
With this implementation of GameCharacter, I now have protection when using a const reference to a GameCharacter (say, as a const parameter to a function.) If I try to call SetPosition() on a const reference to a GameCharacter, the compiler will helpfully point out my mistake. On the other hand, I’m free to call GetPosition() on a const GameCharacter because GetPosition(), by virtue of being a const function, promises that it won’t modify the contents of GameCharacter.
Of course, you might be wondering just who would make a mistake like modifying the values of a or b in a simple function like AddVectors() or trying to SetPosition() on a constant GameCharacter. Probably no one. But, these techniques still apply in larger, more complicated implementations and I’ve never found it safe to trust myself to not make dumb mistakes when writing code. I like to get the compiler to find my mistakes for me whenever it can.
I tend to think of writing const correct code as something akin to brushing one’s teeth. It’s something you need to remember do all the time. It’s easy to skip if you’re feeling lazy. But, if you skip it too much, you end up with cavities (non-const correct code forcing changes in const correct code) that slowly degrade the structure of the entire project. While there is some debate about possible compiler optimizations being made possible by wide-spread const correctness, the primary benefit I find from using const is that it forces me to slow down occassionally and think carefully about how I plan to use any given variable or function. If I know conceptually that a function I’m about to write shouldn’t modify any memory, I make it const. If, in the process of writing said function, I find I have to do something non-const, I revisit my original decision regarding this function’s const-ness. Sometimes, I can simply say that the function is better off as a non-const function. More often that not, I find that I am not actually writing the function I originally envisioned and that I need to rethink either the problem I am trying to solve or the solution with which I am trying to solve it.
English
日本語
Russian Blue