Consider the following class:
template <class T>
struct Test
{
Test() {
if (!f) {
f = []() { std::cout << "it works\n"; };
initialized = true;
}
}
static void check() {
if (f) f();
else std::cout << "f is empty\n";
}
T x{};
inline static std::function<void()> f;
inline static bool initialized = false;
};
An object of such class, if declared globally (Yes, I know it's a bad practice to use global variables), seems to empty the function f
after it is initalized. The following example demonstrates this:
Test<double> t;
int main()
{
t.x = 1.5;
std::cout << "t.x = " << t.x << "\n";
std::cout << std::boolalpha << "initalized: " << Test<double>::initialized << "\n";
Test<double>::check();
return 0;
}
This prints:
t.x = 1.5
initalized: true
f is empty
I expected Test<double>::check();
to print it works
.
However, the above example works as expected, when I do either of the following:
- declare
t
withinmain()
- do not use template for
Test
(just replaceT
withdouble
for example) - make
f
andcheck()
be not static - use plain function pointer instead of
std::function
Does anyone know why this happens?
CodePudding user response:
The problem is related to the order of initialization of static variables which I guess is solved differently for the templated instantiated static variables compared to Test<double>
on different compilers.
inline static Holder f;
is a static variable, so somewhere before entering main it will be default initialized (to an empty function). But Test<double>
is another static variable that will get its own initialization before entering main.
On GCC it happens that
Test<double>
is calledTest<double>::f
is set by the constructor ofTest<double>
- the default constructor of
Test<double>::f
is called, thus emptying the function
This all happens inside __static_initialization_and_destruction_0
GCC method, if you actually use a wrapper object to break on static initialization of the variable you can see what's happening: https://onlinegdb.com/UYEJ0hbgg
How could the compiler know that you plan to set a static variable from another static variable before its construction? That's why, as you said, using static variables is a bad practice indeed.
CodePudding user response:
When you call
Test<double>::initialized
and
Test<double>::check();
the constructor Test() was not called, hence the undefined content of both variables initialized
and f
What you might wanna do is probably calling them
t.check();
t.initialized;