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):
static const int NumTurns = 5
not a definition? Is NumTurns
not initialized to a value of 5
here, and is it not that when a declaration and a definition occurs together, it is called an initialization?static
integral constants not require a definition?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?
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)?
Declarations are important because they inform the compiler or interpreter what the identifying word means, and how the identified thing should be used. A declaration may be optional or required, depending on the programming language.
i.e., declaration gives details about the properties of a variable. Whereas, Definition of a variable says where the variable gets stored. i.e., memory for the variable is allocated during the definition of the variable. In C language definition and declaration for a variable takes place at the same time.
In computer programming, a declaration is a language construct specifying identifier properties: it declares a word's (identifier's) meaning. Declarations are most commonly used for functions, variables, constants, and classes, but can also be used for other entities such as enumerations and type definitions.
The main difference between Function Declaration and Function Definition in C Programming is that Function declaration indicates what the function is and Function Definition indicates what the function does.
Disclaimer: I am not a standard guru.
I suggest you read the following two :
http://www.stroustrup.com/bs_faq2.html#in-class
and:
What is the difference between a definition and a declaration?
Why is static const int NumTurns = 5 not a definition? Is NumTurns not initialized to a value of 5 here, and is it not that when a declaration and a definition occurs together, it is called an initialization?
In high level, definition (as opposed to declaration) instantiates or implements the entity (variable, class, function).
In case of variables, definition makes the variable be allocated on the program memory.
In case of functions - definition gives instructions that can be compiled to assembly instructions.*
The line of code
static const int NumTurns = 5;
does not make NumTurns
be allocated in the program memory by default, so it's only declaration. In order to make (the only) instance of NumTurns
in the program memory you will have to provide the needed definition:
const int MyClass::NumTurns;
Bjarne quote:
You can take the address of a static member if (and only if) it has an out-of-class definition:
class AE {
// ...
public:
static const int c6 = 7;
static const int c7 = 31;
};
const int AE::c7; // definition
int f()
{
const int* p1 = &AE::c6; // error: c6 not an lvalue
const int* p2 = &AE::c7; // ok
// ...
}
Why do static integral constants not require a definition?
They do if you want to take their addresses.
Isn't initialization a definition?
No. initialization is the act of setting initial values in some entity (primitive,object).
void someFunc (){
int x; //x is declared, but not initialized
int y = 0; //y is declared+ initialized.
}
Why is the "only one definition" rule not violated here?
Why would it ? You still have one NumTurns
in the entire code. The symbol MyClas::NumTurns
appears only once. The definition only makes the variable appear on the program memory. ODR rule specify that any symbol may be declared only once.
EDIT:
The question basically boils down to "Why can't the compiler decide on its own?"
I am not a member of the comitee, so I can't give fully legit answer.
My smart guess is that letting the compiler decide things is not the C++ philosophy.
when you let the compiler decide , e.g. where to declare a static integral const,
I, as a developer, may raise the following issues:
1) what happens If my code is a headers-only library? where should my compiler declare the variable? in the first cpp file it encounters? in the file which containes main ?
2) if the compiler decides where to declare the variable , does I have any any guarantee that this variable will be declared alongside with other static variables (which I have manually declared), thus keeping the cache locality tight?
there are more and more questions raised as soon as we approve the mindset of "let the compielr go wild" I think this is a fundamental difference between Java and C++.
Java: let the JVM do its hueristics.
C++: let the developer do his profiling.
eventually, in C++ , the compiler checks that everything makes sence and turn the code into binary,
not do the job instead of the developer.
*or bytecode, if you use managed C++ (boo...)
One of the consequences of the one-definition rule is that a static member of a class can only have one definition. However, if multiple compilation units define it, there would be one definition for every compilation unit within a program. The net effect is that the declaration cannot be a definition without breaking the one-definition rule. In practice, linkers are not typically smart enough to resolve such multiple definitions.
The reason static integral constants do not require a definition is that it is not necessary. If the value is initialised within the class definition, the compiler can just substitute the initialised value whenever it is used. Practically, this means there is no need for that value to actually occupy a memory location in the program (as long as no code computes the address of that constant, in which case a definition would be needed).
Declaration, definition, initialisation are actually separate (albeit related) concepts. A declaration tells the compiler something exists. A definition is a type of declaration that causes that something to exist (so code with visibility of other declarations can refer to it) - for example, allocates memory for it. Initialisation is the act of giving a value. This distinction actually occurs in other parts of the language. For example;
#include <iostream>
int main()
{
int x; // declaration and definition of x
std::cout << x << '\n'; // undefined behaviour as x is uninitialised
x = 42; // since x is not yet initialised, this assignment has an effect of initialising it
std::cout << x << '\n'; // OK as x is now initialised
}
In practice, an initialisation can be part of a declaration, but is not required to be.
Edited to respond to "Edit 3" in the original question:
C++ has a separate compilation model. Java's model relies on capability (smarter linker, run time linking) that C++'s model does not. In C++, if one compilation unit sees a declaration but no definition, the compiler simply assumes the definition is in another compilation unit. Typically (with a lot of build chains) the linker later detects if a necessary definition does not exist, so the linking stage fails. Conversely, if every compilation unit that needed a definition to exist actually created one, the compiler would break the "one definition rule", and a typical dumb linker - which among other things is not smart enough to collapse something defined repeatedly into a single definition - would complain about a multiply-defined symbol.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With