The Software Purist |

TAG | define

Nov/09

18

The Value of Const

In C++, the usage of const is one of those fundamental things that I think can often be confusing for programmers who aren’t experts in the C++ language, so I wanted to discuss it a bit.

Const vs. #define

The first thing to note, especially if you come from a C background is you can make constants by using the #define mechanism.  At first glance, it may seem like const doesn’t provide much advantage and #define may be more flexible.  However, recall that #define is a text-replacement facility.  As such, it doesn’t respect scope or namespaces.  This can make #define cause problems in subtle ways, especially if your constant may trample on other code where the same name is used.  This makes you have to use artificially long names to avoid this issue.  Here’s an example:

#define pi 3.14159265

However, now imagine you have a class called Math with a helper method which calculates pi based on the precision template parameter:

#include "common.h"

template <class TPrecision>
class Math
{
public:
	TPrecision pi()
	{
		// calculate pi to the precision specified by the template
		...
	}
}

To avoid this issue, you wind up having to do something like this:

#define MYLIBRARY_PI 3.14159265

The next thing is let’s say you you also want a constant for Two Pi.  I think this is valid and useful in some contexts.  If you use the preprocessor mechanism, you might code it like this:

#define MYLIBRARY_TWO_PI 3.14159265*2

However, this can cause problems with operator precedence, as you might expect, since you can come up with combinations where this might not do exactly what you expect.  So, then you need to protect your preprocessor macro with ()’s.

There are additional gotchas which we can go into.  The main point is that preprocessor macros require a lot of care.  The usual rationale for using them is performance or space benefits.  Yet, this isn’t accurate, because the C++ const mechanism for basic types can be optimized to use no additional space unless the address is referenced (which would instead be illegal for a #define).  The performance is ultimately the same, and sometimes faster, since a constant like TWO_PI might get you in the troubling case of recalculating two pi at every instance depending on optimization settings.

Const in Regards to Performance

The second group of confusion in the const argument is whether the const mechanism actually helps out with performance in C++.  In theory, it should.  In practice, it doesn’t.  The benefits of const are for documenting your intentions and letting the compiler aide you as to using code as it was intended.  So, for example, if a parameter is marked as const (should be const-reference), and you try to modify it, you will get an error.

So the question is why do programmers often feel that const should help performance?  In theory, it should because if you know a variable in unchanged, there are optimizations you can use.  In practice, you can’t, muchly attributed to a loophole in the language: const_cast.  Const_cast gives you the ability to modify a variable marked as const, thus removing this potential guarantee.  In addition, there is also the risk of non-const pointers modifying the data, so they would also have been validated to not exist.  Ultimately, this is too much work for any compiler and so it isn’t really implemented in practice.

Links:
http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.14
http://www.gotw.ca/gotw/081.htm

· ·

Theme Design by devolux.nh2.me