The EVILS of C++: Static Initialization


Never Do This

Here is something you can do in C++, that you should (probably) never do.

class MyFancyClass {

void MyFancyClass () : whatever (5) {

init_script_state (L);

};

int whatever;

script_state* L;

}

extern MyFancyClass MyFancyClass_Default;

Why? Because you have no control over when init_script_state (L) will be called. In fact, it will be called before main (), in something called __static_initialization_and_destruction_0 (). This is because MyFancyClass_Default is a static global instance of MyFancyClass.

What Happened to Me Today

This cropped up in my overhaul/fixing of Venture the Void source code, which I'm getting to work on Vista and also fixing some bugs.

Imagine if you have something like what I had, which was something like this:

int main () {

init_error_logs (); // initialize error reporting

// ... more code (of course!)

};

void init_script_state (script_state* L) {

if (L != 0) log_error ("initializing non-null script state");

lua_open (L);

};

What's happening is that your log_error () will be called before main (), so your error logging isn't even set up! If you are at all from planet earth, as opposed to planet C++, you aren't going to expect this.

To Track These Down

What I'd reccomend, if you have a problem along these lines, fire up GDB and put a "break exit". Then, on exit, do a stack trace and you should be able to see what particular static class is causing the problem.

An Alternative

The trick is, it seems sometimes useful to have for instance a "default" object available. Like, for me, certain AI routines didn't care about AI state. So I created a default AI state class and passed it in. This was actually bad for other reasons, but you can imagine wanting to have singletons, can't you?

What I would reccomend, is making your defaults a pointer, and creating them manually in main (). Yeah, yer gunna hafta dereference these pointers. Yeah, yer gunna hafta put the initializations in manually.

But think about it: is it really smart to let the compiler decide what order your lines code should execute in, based maybe on some arbitrary thing like the order of libraries passed to the linker? Duh!

2009-08-13


◀ Back