I have classes with side effects in their constructors, and objects of these classes are global objects that have static storage duration. During the initialization these objects register their classes in a special map, and it is important for these registrations to happen before this map is used for other purposes.
The classes and their global objects are defined in separate translation units, and according to the dynamic initialization of non-block variables rules, the initialization can be deferred until other functions or variables from these translation units are used, and that may mean that the initialization is deferred indefinitely.
I'm looking for a way to avoid deferred initialization of these global objects. Saying that I mean that the constructors of the objects shall be called either before main or right after its start, but all the changes shall be done inside translation units of these objects. In other words, whenever one more translation unit with global objects is added, no other translation unit shall be modified.
Update: here is an example:
struct Base {
};
extern void regFactoryMethod(std::function<std::shared_ptr<Base>()>);
struct Object : Base {
struct Registrator {
Registrator() {
regFactoryMethod([](){ return std::make_shared<Object>(); });
}
};
static Registrator registrator;
};
Object::Registrator Object::registrator;
The idea is that the Object::Registrator::Registrator() is automatically called. But it is not guaranteed that it would, as this call may be deferred:
It is implementation-defined whether the dynamic initialization of a non-block non-inline variable with static storage duration is sequenced before the first statement of main or is deferred. If it is deferred, it strongly happens before any non-initialization odr-use of any non-inline function or non-inline variable defined in the same translation unit as the variable to be initialized. It is implementation-defined in which threads and at which points in the program such deferred dynamic initialization occurs.
As you noted in your question, it is implementation-defined whether dynamic initialization is deferred to the first non-initialization odr-use of a non-inline translation unit function/variable directly or indirectly through
main.There is also no other standard approach to execute code before
mainis entered.So, I don't think you can get a guarantee that works independent of the implementation. The standard is also covering use cases such as dynamic loading of libraries at runtime, e.g. with
dlopen. In these cases it cannot be possible to execute code contained in the library beforemainis entered.You'll have to look for implementation guarantees or implementation specific features. For example with GCC/binutils on Linux, as long as you don't link with
--as-needed,--gc-sections, etc., and you ignoredlopen, I think there won't be any deferred initialization.