C++: When (And How) Are C++ Global Static Constructors Called

C++: When (and how) are C++ Global Static Constructors Called?

When talking about non-local static objects there are not many guarantees. As you already know (and it's also been mentioned here), it should not write code that depends on that. The static initialization order fiasco...

Static objects goes through a two-phase initialization: static initialization and dynamic initialization. The former happens first and performs zero-initialization or initialization by constant expressions. The latter happens after all static initialization is done. This is when constructors are called, for example.

In general, this initialization happens at some time before main(). However, as opposed to what many people think even that is not guaranteed by the C++ standard. What is in fact guaranteed is that the initialization is done before the use of any function or object defined in the same translation unit as the object being initialized. Notice that this is not OS specific. This is C++ rules. Here's a quote from the Standard:

It is implementation-defined whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) of an object of
namespace scope is done before the first statement of main. If the initialization is deferred to some point
in time after the first statement of main, it shall occur before the first use of any function or object defined
in the same translation unit as the object to be initialized

When does the constructor of a global object get called?

When does the constructor of the global object get called? Right before main is executed?

Essentially, yes. Within a translation unit, objects are constructed in the order that they appear. Across translation units, the order is undefined.

Objects are destroyed in the opposite order to their construction.

For gcc (and I think, also, clang), see also: How exactly does __attribute__((constructor)) work?

In what order are global constructors called

Global variables are initialized in the order in which they're declared. So their constructor will be called in the same order in which they're initialized. This is true within one translation unit. However, the initialization order across multiple translation-units is not defined by the language specification.

And their destructors are called in the reverse order of their initialization as usual.

static constructors in C++? I need to initialize private static objects

To get the equivalent of a static constructor, you need to write a separate ordinary class to hold the static data and then make a static instance of that ordinary class.

class StaticStuff
{
std::vector<char> letters_;

public:
StaticStuff()
{
for (char c = 'a'; c <= 'z'; c++)
letters_.push_back(c);
}

// provide some way to get at letters_
};

class Elsewhere
{
static StaticStuff staticStuff; // constructor runs once, single instance

};

Which is called first, DllMain() or global static object constructor?

MSDN's DllMain documentation says:

If your DLL is linked with the C
run-time library (CRT), the entry
point provided by the CRT calls the
constructors and destructors for
global and static C++ objects.
Therefore, these restrictions for
DllMain also apply to constructors and
destructors and any code that is
called from them.

Since the code within DllMain may use the static objects, the static objects must be constructed before DllMain is run for DLL_PROCESS_ATTACH, and destroyed after it is run for DLL_PROCESS_DETACH.

You can verify this with a simple test exe and test dll.

EXE:

int _tmain(int argc, _TCHAR* argv[])
{
wprintf(L"Main, loading library\n");
HMODULE h = LoadLibrary(L"Test.dll");

if (h)
{
wprintf(L"Main, freeing library\n");
FreeLibrary(h);
}

wprintf(L"Main, exiting\n");
return 0;
}

DLL:

struct Moo
{
Moo() { wprintf(L"Moo, constructor\n"); }
~Moo() { wprintf(L"Moo, destructor\n"); }
};

Moo m;

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
wprintf(L"DllMain, DLL_PROCESS_ATTACH\n");
break;
case DLL_THREAD_ATTACH:
wprintf(L"DllMain, DLL_THREAD_ATTACH\n");
break;
case DLL_THREAD_DETACH:
wprintf(L"DllMain, DLL_THREAD_DETACH\n");
break;
case DLL_PROCESS_DETACH:
wprintf(L"DllMain, DLL_PROCESS_DETACH\n");
break;
default:
wprintf(L"DllMain, ????\n");
break;
}
return TRUE;
}

Together those will print:

Main, loading library
Moo, constructor
DllMain, DLL_PROCESS_ATTACH
Main, freeing library
DllMain, DLL_PROCESS_DETACH
Moo, destructor
Main, exiting

As you can see, the static object is constructed before DllMain(...,DLL_PROCESS_ATTACH,...) and destroyed after DllMain(...,DLL_PROCESS_DETACH,...)

What is a static constructor?

C++ doesn’t have static constructors but you can emulate them using a static instance of a nested class.

class has_static_constructor {
friend class constructor;

struct constructor {
constructor() { /* do some constructing here … */ }
};

static constructor cons;
};

// C++ needs to define static members externally.
has_static_constructor::constructor has_static_constructor::cons;

How to avoid using static constructor in c++?

  1. Static constructor is an unfortunate name here. I think that they mean here any variable initialization which will be run before main(). For example, a global variable like this:int a = fn();. It will call fn() before main().

  2. No, it doesn't mean that. If a global variable is statically initialized, it avoids the fiasco. For example, int a = 2 will be statically initialized. Or a global object with constexpr constructor will be statically initialized too.

  3. You must use global variables which can be statically initialized. Or you can just remove all global variables altogether. In my opinion, almost all global variables are indicators of bad design, they should be avoided if it is possible. I don't know LLVM's exact solution for this, though.



Related Topics



Leave a reply



Submit