Could someone please explain me this example from the most authoritative ISO C++ FAQ? The code goes like this:
// Fred.h
class Fred {
public:
static const int maximum = 42;
// ...
};
// Fred.cpp
#include "Fred.h"
const int Fred::maximum;
// ...
And the statement I can't get is:
If you ever take the address of Fred::maximum, such as passing it by reference or explicitly saying &Fred::maximum, the compiler will make sure it has a unique address. If not, Fred::maximum won’t even take up space in your process’s static data area.
Compiler processes .cpp files separately and does not know what other files do with data defined in the one currently being processed. So, how can compiler decide if it should allocate a unique address or not?
The original item is here: https://isocpp.org/wiki/faq/ctors#static-const-with-initializers
The FAQ entry says that const int Fred::maximum;
must be defined in exactly one compilation unit. However, this is only true if the variable is odr-used by the program (for example, if a reference is bound to it).
If the variable is not odr-used then the definition can be omitted.
However, if the variable is actually odr-used but has no definition, then it is undefined behaviour with no diagnostic required. Typically, if the variable's address is required but the definition was omitted, a good quality linker would omit an "undefined reference" error.
But you don't always want to be relying on particular manifestations of undefined behaviour. So it is good practice to always include the definition const int Fred::maximum;
.
The quoted paragraph in your question is meant to address a potential programmer concern: "Well, can't I save 4 bytes in my static data area by omitting the definition in some cases?"
It is saying that the compiler/linker could perform whole program analysis, and make its own optimization decision to omit the definition once it has determined that the definition was not used.
Even though the line const int Fred::maximum;
is defined as allocating memory for an int
, this is a permitted optimization because there is no way that a conforming program could measure whether or not memory had actually been allocated for the int
which is not odr-used.
The author of that FAQ entry clearly expects that a compiler/linker would in fact do this.
The wording in the Standard about odr-use is designed to support the following model of compilation/linking:
It does not require the compiler to produce an "undefined reference" error message because this would make it harder for compilers to optimize. Another stage of optimization might happen to entirely remove the part of the object file containing the reference. For example, if it turned out the odr-use only ever occurred in a function that was never called.