Using Constants in Headers

Started by
19 comments, last by the_edd 11 years, 4 months ago
... and this is how the Microsoft .h files are organized.

*Cringe*

The windows headers aren't exactly the pinnacle of clean non-namespace-polluting headers...
Advertisement
You really got the wrong conclusion from this. You don't know if using a const variable wastes any memory, so that's a terrible reason to pick one over the other. An optimized build with g++ generates identical code for both.

A const variable behaves like any other variable, while a macro constant has surprises: you can't take its address, it doesn't have a namespace, it doesn't obey the usual scoping rules, you can't access its value from a debugger, it can't be an object of a class...

You should write your code to be as clear as possible, minimizing surprises, not whether you might save 4 bytes (which you won't anyway). And therefore you should prefer using const variables over macros to represent constants.
Alvaro,

Thank you for that additional input. Could you possibly link or attach an example of a (if possible complex) header defining const variables that use the features you list above such as namespaces, being objects in classes, having their addresses taken, etc. I guess I need to see what kind of complexity doing this entails, and if I will ever use those features.

-Dave Ottley

I wonder as I wander...

http://www.davesgameoflife.com

Good examples of the namespacing problem come directly from Microsoft's <windows.h> header itself.

I bet many people here have hit the problem of trying to std::numeric_limits<int>::max(), or std::max(a, b) after #include-ing <windows.h>, only have the compiler to spit a weird error at them. This is because <windows.h> uses the preprocessor to define 'min' and 'max' macros.

Another example of preprocessor damage, also caused by <windows.h>:


#include <windows.h>

namespace fs
{
bool DeleteFile(const fs::Path &amp;amp;filename)
{
// ...
}
}


This won't compile without additional hacks. This is because <windows.h> uses the preprocessor to define "DeleteFile" as either "DeleteFileA" or "DeleteFileW", depending on whether or not you've defined UNICODE. I've even gone to the care of putting my DeleteFile in its own namespace. But it doesn't make a difference to the preprocessor.

Not only does the preprocessor not respect C++ namespaces, but there's no way of putting macros themselves in to any kind of namespace, meaning that everyone has to (or really should) add a prefix to the front of their macros.

So <windows.h> is a horrible header. I could list a number of other real-world examples where it has damaged perfectly reasonable code. I actually have a policy to never include it in a public header because of the carnage it can cause. I would not recommend using it for inspiration!

Though sometimes useful, the preprocessor should be avoided where possible, especially if there's an alternative, which in this case there is. Use "const int MAX_INTS = 1000;" instead. You really shouldn't be worrying about wasting 4 bytes here or there.
The code in the header file would look exactly as I posted above, except for possibly being in a namespace. But if you aren't using namespaces [yet], there is no point in putting this particular thing in a namespace.

I can't post any code from work, but we do this type of thing all the time there.

Just test to print the value of the constant from a debugger, and you'll immediately see one of the benefits of using a const variable.
Keep in mind that the MS windows headers are designed to be used from C as well as C++. So while there are (reasonably) good reasons for what they do in their code, you should only copy them if you are working under the same kind of constraint.

Also, for integral constants, another option is using an enum. Like a #define it never occupies storage, but like const variables it respects scope.
If I have a const string I access from several places, should I declare it extern and move definition to a .cpp or make it static? Since just making it const string in the header would create multiple objects?
That's not something you really need to worry about. Most linkers will fold identical constant data (including strings) into a single instance. Ex: MSVC's /opt:icf behavior.
Thank you all for your kind responses. So, should I put a namespace i.e. Constants:: around my constants, or would that be a waste of keystrokes?

I wonder as I wander...

http://www.davesgameoflife.com

Unless your constants have some sort of logical reason that they should be either grouped together or sectioned off from other symbols, then there's no point in creating a namespace just for constants. For example, you might group constants that form flags together or constants for private use separate from other symbols. But there's no point to dumping all your constants in a namespace just to have a namespace.

This topic is closed to new replies.

Advertisement