Reputation: 2326
Just for fun, I was investigating the order of dynamic initialization of static objects. In a file name t.h, I put
struct T {
static std::vector<std::string> me;
static int add(std::string s) { me.push_back(s); return me.size(); }
};
(Plus needed headers for vector and string.) "std::vector T::me" is in t.cpp. The file main.cpp prints out the values in T::me:
#include "t.h"
#include <iostream>
using namespace std;
int main()
{
T::me.push_back("main");
cout << "T::me.size()=" << T::me.size() << endl;
for (unsigned i = 0; i<T::me.size(); ++i) {
cout << i << "-" << T::me[i] << endl;
}
return 0;
}
next, I create "a.cpp" and put the following in it:
#include "t.h"
int a = T::add("a");
Do the similar for file b.cpp and c.cpp using "b" and "c" as appropriate. Compile using g++ *.cpp, then run ./a.out. The order of static initialization from compilation unit to compilation unit is unspecified. In my case it is consistently in reverse alphabetical order. I get: 3 - c 2 - b 1 - a 0 - main
No problems so far.
Now I create u.cpp like a.cpp but using "u". Recompile/rerun, "u" does not show up in the list.
Is it because I never referenced u? I never referenced a,b,c, but I change main:
#include "t.h"
#include <iostream>
using namespace std;
extern int u;
int main()
{
cout << "u=" << u << endl;
T::me.push_back("main");
cout << "T::me.size()=" << T::me.size() << endl;
for (unsigned i = 0; i<T::me.size(); ++i) {
cout << i << "-" << T::me[i] << endl;
}
return 0;
}
The program prints out "u=2", but "u" is not in the list. Shouldn't u have been dynamically initialized before use and, therefore, T::me have been updated to include "u"? I think there should be a better explanation than that u comes after t in the alphabet.
Upvotes: 3
Views: 553
Reputation: 2326
I've got it. Simple, really. T::me is zero initialized statically according to the rules of C++. There is a constructor, however, to run dynamically. There's no guarantee when that constructor runs. It is apparently - in this case - running after u is initialized.
Upvotes: 3
Reputation: 477100
It seems that the compilation linking order matters:
g++ -o m a.cpp u.cpp t.cpp main.cpp
gives
a=2
u=1
T::me.size()=3
0-u
1-a
2-main
but
g++ -o m main.cpp t.cpp a.cpp u.cpp
gives
a=2
u=1
T::me.size()=1
0-main
and reversing a.cpp
and u.cpp
in the last case causes a=1
and u=2
.
Interesting!
Upvotes: 1