According to information on other sources C++ distinguish two kinds of initialization of static variables:
static - if variable is initialized by putting it within initial value to special section in executable file.
dynamic - if initial value of static variable has too be computed
There is many discussion regarding order of dynamic initialization constructors calls. But I didn't found info how to wait until all dynamic initialization of all static variables in executable finishes. Or from other side how to call by hands this initialization in the indirect/generic way.
I use static variables initialization for loose coupling of kind of plugin architecture. I have plugin1.c, plugin2.c ... and static variable inside of plugin1.c
static bool installed = plugin1_install();
But in main I need to wait until all plugins installed.
The same thing I use was suggested here 1. As the answer to following question
I wanted to write a shared library for my program. However, I need the library to have some self initialization routines before anyother functions in the library are called...
Answer:
C++ itself supports global initializations of things. You can do things like:
int global_variable=some_global_function();
This would be illegal in C, but is legal in C++.
Can I implement feature I need with help of __CTOR_LIST__
?
There is no need to wait. In C++ program startup is singly-threaded so once you get to the first instruction of main
all global static storage duration variables will have been already initialized.
The problem you read about is however that there are little guarantees about what is the order of initialization during that startup phase. In other words if the initialization of a static object requires the use of another static object then you're possibly in trouble.
My suggestion is try to avoid doing complex processing during the startup phase... and specifically avoid doing anything that could possibly fail. The reason is that during that period (and during its dual at shutdown time) the system is not yet (or not any more) 100% functional and debugging is especially hard. For example in windows systems a segfault during shutdown is often silenced and with some environments debugging is not working properly before the start of main
.
If your initialization phase is just however plugin registration then this can be made safe by using a lazy singleton pattern for the registry:
struct Plugin
{
Plugin(const std::string& name);
...
};
std::map<const char *, Plugin *>& registered_plugins()
{
static std::map<const char *, Plugin *> directory;
return directory;
}
Plugin::Plugin(const char * name)
{
registered_plugins()[name] = this;
}
...
struct MyPlugin1 : Plugin
{
MyPlugin1() : Plugin("Plugin-1")
...
} MyPlugin_instance;
In the above code MyPlugin_instance
variable will be created during startup (before main
) but the plugin registry is known to have been already correctly constructed because it's not a global but a function static, and those variables are initialized the first time their scope is entered.
Declaring instead the global plugin directory as a static duration global would be problematic because if plugins and the directory are not in the same compilation unit then there is no guarantee about the order of initialization; therefore it could be possible that the plugin gets constructed and tries to register itself in a map that is not yet constructed.
What could still be dangerous with this approach is however accessing the singleton in the destructor of a static duration object because - like for construction - the risk is that someone will try to use the registry after it has been already destroyed.
My suggestion is anyway to try to keep this kind of pre-main processing at a minimum; anything non trivial can be a source of big and hard to debug problems. Startup and shutdown, if possible, should be IMO kept under clear control and singly threaded.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With