Confused about constants defined in namespaces

Started by
8 comments, last by phresnel 15 years, 1 month ago
Hi, I used to operate under the assumption that in C++, constants defined in a header file ... like so

// Constants.h
namespace Constants
{
    const int theInt = 6;
}

would be shared by all compilation units including this header. That is, instead of each compilation unit getting its own copy of theInt, all compilation units including Constants.h would share one copy of theInt. However, I just compiled a minimal project (Visual C++ 2005) that has 2 compilation units CompilationUnit1.cpp and CompilationUnit2.cpp that both pull in Constants.h and then print the address of Constants::theInt, and surprisingly the addresses did not match! :o What do I need to do if I want all compilation units to share the same instance of Constants::theInt?
Advertisement
Hmm, apparently if I declare theInt 'extern' and then initialize it in a separate cpp (Constants.cpp), all compilation units really get to share the same copy of theInt. Is that the recommended way of sharing constants across compilation units?
Yes it is!
“Always programm as if the person who will be maintaining your program is a violent psychopath that knows where you live”
Quote:Original post by Red Ant
Is that the recommended way of sharing constants across compilation units?

The recommended way for integral constants is to refrain from taking their addresses, then they don't even consume any memory in the first place (in most cases).
Quote:Original post by DevFred
The recommended way for integral constants is to refrain from taking their addresses, then they don't even consume any memory in the first place (in most cases).


Ah okay, so I can continue just declaring my constants like this

// constants.hnamespace Constants{    const int a = 4444;    const bool x = true;}


and then pull in constants.h where ever I need to access them? I was just worrying that I'd unnecessarily increase my memory footprint by having each compilation unit use its own copy of each constant.
Quote:Original post by DevFred
Quote:Original post by Red Ant
Is that the recommended way of sharing constants across compilation units?

The recommended way for integral constants is to refrain from taking their addresses, then they don't even consume any memory in the first place (in most cases).


Even better: Use an enum.

// Constants.hnamespace Constants{    enum { theInt = 6 };}


Now it is even forbidden to take the address, and you are guaranteed that this is a pure compile time construct. No need to kludge with extern or static keywords.
Quote:Original post by phresnel
Even better: Use an enum.



I do where ever possible but sometimes you need a const double, bool or whatever.
Quote:Original post by Red Ant
I do where ever possible but sometimes you need a const double, bool or whatever.


Bool will also work:
enum { is_little_endian = true };


But you are right about non integral types. The only "hardened" solution that comes to mind is to use #define macros, but that I'd avoid (just alone because of scoping issues). For my code, const-float duplication is not so relevant, so I just sticked to static const floats and doubles.

If duplication is an issue, then of course make them extern, and put the definitions into a file named "constants.[cpp|cc|cxx|etc.]" or give it a finer grained name like "planet-size-constants.[...]".

edit: typo

[Edited by - phresnel on March 12, 2009 7:54:40 AM]
Quote:Original post by Red Ant
I was just worrying that I'd unnecessarily increase my memory footprint by having each compilation unit use its own copy of each constant.


This doesn't happen because in general (what DevFred was alluding to) the constant will simply be inlined at each point of usage when possible, and then the static constant value will be recognized as a "dead" value and optimized out of the binary. But as soon as you try to take the address of the constant, it has to exist so that it can have an address, and won't be optimized out.
Minor Addition: If you have static const member variables of type float, you have to implant them in some translation unit. Just happened to me this morning, when I added a generic version of an epsilon- and an infinity- constant.

This topic is closed to new replies.

Advertisement