views:

147

answers:

4

If i have a header file foo.h and a source file foo.cpp, and foo.cpp contains something along the lines of:

#ifdef WIN32
class asdf {
   asdf() { startup_code(); }
   ~asdf() { cleanup_code(); }
};
asdf __STARTUP_HANDLE__
#else
//unix does not require startup or cleanup code in this case
#endif

but foo.h does not define class asdf, say i have an application bar.cpp:

#include "foo.h"
//link in foo.lib, foo.dll, foo.so, etc
int main() {
   //do stuff
   return 0;
}

If bar.cpp is compiled on a WIN32 platform, will the asdf() and ~asdf() be called at the appropriate times (before main() and at program exit, respectively) even though class asdf is not defined in foo.h, but is linked in through foo.cpp?

+4  A: 

Yes -- but be very careful. The order in which static objects (like your asdf object) are initialized is undefined. So it is undefined behavior if any other object tries to reference your object before main().

Also, __STARTUP_HANDLE__ is not a valid identifier. Double-underscores are not allowed in any identifier (even macros), and a single-underscore followed by a capital letter is also not allowed.

rlbond
A: 

As long as the objects (foo.o) themselves are linked into the executable, this will work (assuming the static initialization order fiasco doesn't hit you). If you're pulling it in from a library (foo.lib), though, it won't unless you explicitly mark the object as an "active object," but I don't remember how to do that in MSVC.

dash-tom-bang
A: 

On Windows and with DLL's you have the possibility to use the function DllMain that will be called at load etc

BOOL WINAPI DllMain(HINSTANCE hinstDLL,
                    DWORD fdwReason,
                    LPVOID lpvReserved) {  

  switch (fdwReason) {

  case DLL_PROCESS_ATTACH:    
    break;

  case DLL_THREAD_ATTACH:
    break;

  case DLL_THREAD_DETACH:
    break;

  case DLL_PROCESS_DETACH:
    break;

  default:
    break;
  }

  return TRUE;
}
epatel
To complement this, on Linux you can tag plain *functions* that take no arguments as having the `constructor` or `destructor` attribute. The linker then arranges for them to be called at program start/library load (or exit/unload) as part of the mechanism that supports C++ objects with those lifetimes.
Donal Fellows
+1  A: 

If it ain't broke, don't fix it. Look out for the static initialization order issue, as the other answers say. But you really should fix that reserved identifier.

__STARTUP_HANDLE__ does work similar to a runtime library, and runtime libraries use names like that, but it's not part of the runtime library so that name isn't allowed.

#ifdef WIN32
namespace { // anonymous namespace - no outside access
class asdf {
   asdf() { startup_code(); }
   ~asdf() { cleanup_code(); }
} x; // to create an instance
}
Potatoswatter
Why don't you need to name the class? Doesn't the compiler need to have an identifier for the type such that it can decide the name of the constructor/destructor?
Robert Mason
@Robert: sorry, that was stupid before. Yes, the class needs to have a name to have a constructor :vP
Potatoswatter