In Effective C++ (3rd Ed.), Item 2 (Prefer const
, enum
and inline
to #define
), the code segment for class-specific constants read:
class GamePlayer {
private:
static const int NumTurns = 5; // constant declaration
int scores[NumTurns]; // use of constant
...
};
The book then says (in my own words) that static const int NumTurns = 5;
is not a definition, which is normally required by C++ for class members unless it is a static integral constant whose address is never used. If the above is not true for the constant or if the compiler insists on a definition for any reason, the definition should be provided in the implementation file as follows:
const int GamePlayer::NumTurns; // definition of NumTurns; see
// below for why no value is given
According to the book (also in my own words), no value is given in the definition because it's already given in the declaration.
This is confusing what I thought I already know about the definitions of declaration and definition (and I double-checked on Google before asking this question):
- Why is
static const int NumTurns = 5
not a definition? IsNumTurns
not initialized to a value of5
here, and is it not that when a declaration and a definition occurs together, it is called an initialization? - Why do
static
integral constants not require a definition? - Why is the second code snippet considered to be a definition when no value is defined, yet the declaration inside the class which contains the value is still not one (essentially going back to my first question)?
- Isn't initialization a definition? Why is the "only one definition" rule not violated here?
It's possible I'm just confusing myself here at this point, so can someone kindly re-educate me from scratch: Why are those two lines of code declarations and definitions and not the other, and are there any instances of initialization there? Is initialization also a definition?
Credit: Code snippets are directly quoted from the book.
Edit: With additional reference to What is the difference between a definition and a declaration?
- A declaration introduces the identifier and type
- A definition instantiates and implements
So, yeah...that doesn't seem to be what's going on here.
Edit 2: I consider it is possible that compilers may optimize a static integral constant by not storing it in-memory and just substituting it inline in the code. But if NumTurns
address is used, why doesn't the declaration change into a declaration+definition automatically since the instantiation is already there?
Edit 3: (This edit has less to do with the original question, but is still outstanding from it. I place it here so that I don't need to copy-paste into the comments for each answer below. Please answer me for this in the comments. Thanks!)
Thanks for the answers. My head is much clearer now, but the last question from Edit 2 still remains: If the compiler detects conditions in the program where a definition is needed (eg. &NumTurns
is used in the program), why doesn't it just automatically reinterpret static const int NumTurns = 5;
as a declaration & definition instead of declaration-only? It has all the syntax a definition anywhere else in a program would have.
I come from a Java background in school, and have not needed to make separate definitions like these for static members in the manner above. I know C++ is different, but I want to know why the above is like this. A static integral member being substituted inline if the address is never used sounds more like an optimization to me rather than a fundamental feature, so why is it I need to work around it (providing a separate statement as the definition when the conditions aren't met even though the original statement's syntax is sufficient) rather than the other way round (compiler treating the original statement as a definition when it is needed to have one since syntax is sufficient)?
NumTurns
into existence). The= 5
in the declaration only sets a default, it does not set a value. The definition (const int GamePlayer::NumTurns;
) uses that default; it could provide a non-default initialization as well. – Glossematicsstatic
variable in a single translation unit / object-file (loosely speaking, a single .c++/.cpp/.cc/.cxx or whatever you like to call your "implementation" files)... that's the lesson to be learnt from this question & the answers. – Foreignismconst
variables in the header without assignment, and defining them in one implementation file with actual values. cont... – Foreignismconst
variables, it helps to let the compiler use the variable much as a macro - substituting the constant value where used as a template parameter, to size an array, or other uses at compile time that have no need of the address. So, think of this as the non-const
model with benefits that arise from letting the value be specified at the declaration. A necessary tolerance to makestatic const
variables a viable, equally efficient but type safe and namespace/scope-respecting alternative to preprocessor defines. – Foreignism