When you have a static global variable in a C++ header file, each translation unit that includes the header file ends up with its own copy of the variable.
However, if I declare a class in that same header file, and create a member function of that class, implemented inline within the class declaration, that uses the static global variable, for example:
#include <iostream>
static int n = 10;
class Foo {
public:
void print() { std::cout << n << std::endl; }
};
then I see slightly odd behavior under gcc 4.4:
If I compile without optimization, all uses of the member function use the copy of the variable from one of the translation units (the first one mentioned on the g++ command line).
If I compile with -O2
, each use of the member function uses the copy of the variable from the translation unit in which the case is made.
Obviously this is really bad design, so this question is just out of curiosity. But my question, nonetheless, is what does the C++ standard say about this case? Is g++ behaving correctly by giving different behavior with and without optimization enabled?
Static local variables are not allowed to be defined within the body of an inline function. C++ functions implemented inside of a class declaration are automatically defined inline.
A global variable can be accessed from anywhere inside the program while a static variable only has a block scope. So, the benefit of using a static variable as a global variable is that it can be accessed from anywhere inside the program since it is declared globally.
A global static variable is one that can only be accessed in the file where it is created. This variable is said to have file scope. In C, the preprocessor directive #define was used to create a variable with a constant value. This still works in C++, but problems could arise.
In C++ (before C++17 version), we cannot initialize the value of static variables directly in the class. We have to define them outside of the class.
The standard says (3.2/5):
There can be more than one definition of a class type (clause 9), ... provided the definitions satisfy the following requirements ... in each definition of D, corresponding names, looked up according to 3.4, shall refer to an entity defined within the definition of D, or shall refer to the same entity
This is where your code loses. The uses of n
in the different definitions of Foo
do not refer to the same object. Game over, undefined behavior, so yes gcc is entitled to do different things at different optimization levels.
3.2/5 continues:
except that a name can refer to a const object with internal or no linkage if the object has the same integral or enumeration type in all definitions of D, and the object is initialized with a constant expression (5.19), and the value (but not the address) of the object is used, and the object has the same value in all definitions of D
So in your example code you could make n
into a static const int
and all would be lovely. It's not a coincidence that this clause describes conditions under which it makes no difference whether the different TUs "refer to" the same object or different objects - all they use is a compile-time constant value, and they all use the same one.
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