So, I've been experimenting with static class fields (especially the constant ones), and got myself into.... this:
#include <iostream>
#include <conio.h>
class Test {
public:
Test() { std::cout << "Constructing (Default CTOR)\n"; }
Test(int f) { std::cout << "Constructing (Int arg CTOR)\n"; }
void method() const { std::cout << "Already constructed and being used\n"; }
};
class Stack {
public:
// static const Test what{ 5 }; // - "element of type "const Test" can not have an initializer inside of a class"
// const Test ok{ 5 }; // now it can (?)
static const Test what;
Stack() {
what.method();
}
// Stack() : what{5} {} // can't do that because "what" will be dependent on object creation (which is not how static class fields roll)
};
Stack obj;
const Test Stack::what{};
int main()
{
_getch();
return 0;
}
Output:
Apparently, static const Test what
in Stack
is being used before is has actually been created(?).
After that I ran another test:
#include <iostream>
#include <conio.h>
class Test {
public:
int data;
Test() { std::cout << "CONSTRUCTING (Default CTOR)\n"; } // notice, value-initialization of 'data' has been removed
Test(int f) : data{ f } { std::cout << "CONSTRUCTING (Int arg CTOR)\n"; }
void method() const { std::cout << "ALREADY CONSTRUCTED AND BEING USED :)\n" << data << std::endl; }
};
class Stack {
public:
static const Test what;
Stack() {
what.method();
}
};
Stack obj;
const Test Stack::what{ 5 };
int main()
{
obj.what.method();
_getch();
return 0;
}
In this code I was hoping to see some sort of error, but the output ended up looking like this:
I have some assumptions on what is happening here, but I'm not sure if they're correct. So, if they are, please correct me.
Here are my assumptions:
Basically, static variables are created at the very start of the program (and are value-initialized) and destoyed at the very end of the program (when you actually close your .exe).
In my examples I have a static constant variable what
in the class Stack
and I think it is being created at the beginning of my program value-initialized. That's why its data
field is set 0 and we can use its methods. But I don't think that's correct because it would've output Constructing (Default CTOR)
into the console. So I'm kinda stuck there...
I also can not understand why the commented lines in my first example are illegal. What rules of static/constant class fields do they break exactly?
If you have any idea to what is happening in my examples please explain it.
Thanks for your attention.
Static variables at namespace scope (i.e. not inside a function) are constructed in the order of their definitions in the source file. This ordering only applies between variables in the same source file, not between different source files.
So obj
is always constructed before what
. There are limited things that can be done with objects that have a constructor but before the constructor has been called; and invoking a member function is not one of them (C++14 [basic.life]/5.2). So the call what.method()
in Stack
's constructor causes undefined behaviour.