简体   繁体   中英

Static Initialization Fiasco - On Purpose

Just for fun, I was investigating the order of dynamic initialization of static objects. In a file name th, 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.

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.

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM